1 // --------------------------------------------------------------------------------------------------------------------
2 // <copyright file=
"PhotonNetwork.cs" company="Exit Games GmbH">
3 // Part of: Photon Unity Networking
4 // </copyright>
5 // --------------------------------------------------------------------------------------------------------------------

6
7 using
UnityEngine;
8 using
System;
9 using
System.Collections.Generic;
10 using
ExitGames.Client.Photon;
11 using
Hashtable = ExitGames.Client.Photon.Hashtable;
12
13 #
if UNITY_EDITOR
14 using
UnityEditor;
15 #endif

16
17
18 ///
<summary>
19 ///
The main class to use the PhotonNetwork plugin.
20 ///
This class is static.
21 ///
</summary>
22 ///
\ingroup publicApi
23 public
static class PhotonNetwork
24 {

25     ///
<summary>Version number of PUN. Also used in GameVersion to separate client version from each other.</summary>
26     
public const string versionPUN = "1.50";
27
28     
public static string gameVersion
29     {
30         
get { return networkingPeer.mAppVersion; }
31         
set { networkingPeer.mAppVersion = value; }
32     }

33
34     ///
<summary>
35     ///
This Monobehaviour allows Photon to run an Update loop.
36     ///
</summary>
37     
internal static readonly PhotonHandler photonMono;
38
39     ///
<summary>
40     ///
Photon peer class that implements LoadBalancing in PUN.
41     ///
Primary use is internal (by PUN itself).
42     ///
</summary>
43     
internal static NetworkingPeer networkingPeer;
44
45     ///
<summary>
46     ///
The maximum amount of assigned PhotonViews PER player (or scene). See the documentation on how to raise this limitation
47     ///
</summary>
48     
public static readonly int MAX_VIEW_IDS = 1000; // VIEW & PLAYER LIMIT CAN BE EASILY CHANGED, SEE DOCS
49
50
51     ///
<summary>Name of the PhotonServerSettings file (used to load and by PhotonEditor to save new files).</summary>
52     
public const string serverSettingsAssetFile = "PhotonServerSettings";
53
54     ///
<summary>Path to the PhotonServerSettings file (used by PhotonEditor).</summary>
55     
public const string serverSettingsAssetPath = "Assets/Photon Unity Networking/Resources/" + PhotonNetwork.serverSettingsAssetFile + ".asset";
56
57
58     ///
<summary>Serialized server settings, written by the Setup Wizard for use in ConnectUsingSettings.</summary>
59     
public static ServerSettings PhotonServerSettings = (ServerSettings)Resources.Load(PhotonNetwork.serverSettingsAssetFile, typeof(ServerSettings));
60
61     ///
<summary>Currently used server address (no matter if master or game server).</summary>
62     
public static string ServerAddress { get { return (networkingPeer != null) ? networkingPeer.ServerAddress : "<not connected>"; } }
63
64     ///
<summary>
65     ///
The minimum difference that a Vector2 or Vector3(e.g. a transforms rotation) needs to change before we send it via a PhotonView's OnSerialize/ObservingComponent
66     ///
Note that this is the sqrMagnitude. E.g. to send only after a 0.01 change on the Y-axix, we use 0.01f*0.01f=0.0001f. As a remedy against float inaccuracy we use 0.000099f instead of 0.0001f.
67     ///
</summary>
68     
public static float precisionForVectorSynchronization = 0.000099f;
69
70     ///
<summary>
71     ///
The minimum angle that a rotation needs to change before we send it via a PhotonView's OnSerialize/ObservingComponent
72     ///
</summary>
73     
public static float precisionForQuaternionSynchronization = 1.0f;
74
75     ///
<summary>
76     ///
The minimum difference between floats before we send it via a PhotonView's OnSerialize/ObservingComponent
77     ///
</summary>
78     
public static float precisionForFloatSynchronization = 0.01f;
79
80     ///
<summary>
81     ///
False until you connected to Photon initially. True in offline mode, while connected to any server and even while switching servers but
82     ///
</summary>
83     
public static bool connected
84     {
85         
get
86         {
87             
if (offlineMode)
88             {
89                 
return true;
90             }
91
92             
if (networkingPeer == null)
93             {
94                 
return false;
95             }
96
97             
return !networkingPeer.IsInitialConnect && networkingPeer.State != PeerState.PeerCreated && networkingPeer.State != PeerState.Disconnected && networkingPeer.State != PeerState.Disconnecting && networkingPeer.State != PeerState.ConnectingToNameServer;
98         }
99     }

100
101     ///
<summary>
102     ///
True when you called ConnectUsingSettings (or similar) until the low level connection to Photon gets established.
103     ///
</summary>
104     
public static bool connecting
105     {
106         
get { return networkingPeer.IsInitialConnect && !offlineMode; }
107     }

108
109     ///
<summary>
110     ///
A refined version of connected which is true only if your connection to the server is ready to accept operations like join, leave, etc.
111     ///
</summary>
112     
public static bool connectedAndReady
113     {
114         
get
115         {
116             
// connected property will check offlineMode and networkingPeer being null
117             
if (!connected)
118             {
119                 
return false;
120             }
121
122             
if (offlineMode)
123             {
124                 
return true;
125             }
126
127             
switch (connectionStateDetailed)
128             {
129                 
case PeerState.PeerCreated:
130                 
case PeerState.Disconnected:
131                 
case PeerState.Disconnecting:
132                 
case PeerState.Authenticating:
133                 
case PeerState.ConnectingToGameserver:
134                 
case PeerState.ConnectingToMasterserver:
135                 
case PeerState.ConnectingToNameServer:
136                 
case PeerState.Joining:
137                 
case PeerState.Leaving:
138                     
return false; // we are not ready to execute any operations
139             }
140
141             
return true;
142         }
143     }

144
145     ///
<summary>
146     ///
Simplified connection state
147     ///
</summary>
148     
public static ConnectionState connectionState
149     {
150         
get
151         {
152             
if (offlineMode)
153             {
154                 
return ConnectionState.Connected;
155             }
156
157             
if (networkingPeer == null)
158             {
159                 
return ConnectionState.Disconnected;
160             }
161
162             
switch (networkingPeer.PeerState)
163             {
164                 
case PeerStateValue.Disconnected:
165                     
return ConnectionState.Disconnected;
166                 
case PeerStateValue.Connecting:
167                     
return ConnectionState.Connecting;
168                 
case PeerStateValue.Connected:
169                     
return ConnectionState.Connected;
170                 
case PeerStateValue.Disconnecting:
171                     
return ConnectionState.Disconnecting;
172                 
case PeerStateValue.InitializingApplication:
173                     
return ConnectionState.InitializingApplication;
174             }
175
176             
return ConnectionState.Disconnected;
177         }
178     }

179
180     ///
<summary>
181     ///
Detailed connection state (ignorant of PUN, so it can be "disconnected" while switching servers).
182     ///
</summary>
183     ///
<remarks>
184     ///
In OfflineMode, this is PeerState.Joined (after create/join) or it is ConnectedToMaster in all other cases.
185     ///
</remarks>
186     
public static PeerState connectionStateDetailed
187     {
188         
get
189         {
190             
if (offlineMode)
191             {
192                 
return (offlineModeRoom != null) ? PeerState.Joined : PeerState.ConnectedToMaster;
193             }
194
195             
if (networkingPeer == null)
196             {
197                 
return PeerState.Disconnected;
198             }
199
200             
return networkingPeer.State;
201         }
202     }

203
204     ///
<summary>
205     ///
A user's authentication values used during connect for Custom Authentication with Photon (and a custom service/community).
206     ///
Set these before calling Connect if you want custom authentication.
207     ///
</summary>
208     ///
<remarks>
209     ///
If authentication fails for any values, PUN will call your implementation of OnCustomAuthenticationFailed(string debugMsg).
210     ///
See: PhotonNetworkingMessage.OnCustomAuthenticationFailed
211     ///
</remarks>
212     
public static AuthenticationValues AuthValues
213     {
214         
get { return (networkingPeer != null) ? networkingPeer.CustomAuthenticationValues : null; }
215         
set { if (networkingPeer != null) networkingPeer.CustomAuthenticationValues = value; }
216     }

217
218     ///
<summary>
219     ///
Get the room we're currently in. Null if we aren't in any room.
220     ///
</summary>
221     
public static Room room
222     {
223         
get
224         {
225             
if (isOfflineMode)
226             {
227                 
return offlineModeRoom;
228             }
229
230             
return networkingPeer.mCurrentGame;
231         }
232     }

233
234     ///
<summary>If true, Instantiate methods will check if you are in a room and fail if you are not.</summary>
235     ///
<remarks>
236     ///
Instantiating anything outside of a specific room is very likely to break things.
237     ///
Turn this off only if you know what you do.</remarks>
238     
public static bool InstantiateInRoomOnly = true;
239
240     ///
<summary>
241     ///
Network log level. Controls how verbose PUN is.
242     ///
</summary>
243     
public static PhotonLogLevel logLevel = PhotonLogLevel.ErrorsOnly;
244
245     ///
<summary>
246     ///
The local PhotonPlayer. Always available and represents this player.
247     ///
CustomProperties can be set before entering a room and will be synced as well.
248     ///
</summary>
249     
public static PhotonPlayer player
250     {
251         
get
252         {
253             
if (networkingPeer == null)
254             {
255                 
return null; // Surpress ExitApplication errors
256             }
257
258             
return networkingPeer.mLocalActor;
259         }
260     }

261
262     ///
<summary>
263     ///
The PhotonPlayer of the master client. The master client is the 'virtual owner' of the room. You can use it if you need authorative decision made by one of the players.
264     ///
</summary>
265     ///
<remarks>
266     ///
The masterClient is null until a room is joined and becomes null again when the room is left.
267     ///
</remarks>
268     
public static PhotonPlayer masterClient
269     {
270         
get
271         {
272             
if (networkingPeer == null)
273             {
274                 
return null;
275             }
276
277             
return networkingPeer.mMasterClient;
278         }
279     }

280
281     ///
<summary>
282     ///
Allows the current Master Client to assign someone else as MC - custom selection should pick the same user on any client.
283     ///
</summary>
284     ///
<remarks>
285     ///
The ReceiverGroup.MasterClient (usable in RPCs) is not affected by this (still points to lowest player.ID in room).
286     ///
Avoid using this enum value (and send to a specific player instead).
287     ///
288     ///
If the current Master Client leaves, PUN will detect a new one by "lowest player ID". Implement OnMasterClientSwitched
289     ///
to get a callback in this case. The PUN-selected Master Client might assign a new one.
290     ///
291     ///
Make sure you don't create an endless loop of Master-assigning! When selecting a custom Master Client, all clients
292     ///
should point to the same player, no matter who actually assigns this player.
293     ///
294     ///
Locally the Master Client is immediately switched, while remote clients get an event. This means the game
295     ///
is tempoarily without Master Client like when a current Master Client leaves.
296     ///
297     ///
When switching the Master Client manually, keep in mind that this user might leave and not do it's work, just like
298     ///
any Master Client.
299     ///
</remarks>
300     ///
<param name="masterClientPlayer">The player of the next Master Client.</param>
301     ///
<returns>False when this synced action couldn't be done. Must be online and Master Client.</returns>
302     
public static bool SetMasterClient(PhotonPlayer masterClientPlayer)
303     {
304         
if (!VerifyCanUseNetwork() || !isMasterClient)
305         {
306             
return false;
307         }
308
309         
return networkingPeer.SetMasterClient(masterClientPlayer.ID, true);
310     }

311
312     ///
<summary>
313     ///
This local player's name.
314     ///
</summary>
315     ///
<remarks>Setting the name will automatically send it, if connected. Setting null, won't change the name.</remarks>
316     
public static string playerName
317     {
318         
get
319         {
320             
return networkingPeer.PlayerName;
321         }
322
323         
set
324         {
325             networkingPeer.PlayerName =
value;
326         }
327     }

328
329     ///
<summary>
330     ///
The full PhotonPlayer list, including the local player.
331     ///
</summary>
332     
public static PhotonPlayer[] playerList
333     {
334         
get
335         {
336             
if (networkingPeer == null)
337                 
return new PhotonPlayer[0];
338
339             
return networkingPeer.mPlayerListCopy;
340         }
341     }

342
343     ///
<summary>
344     ///
The other PhotonPlayers, not including our local player.
345     ///
</summary>
346     
public static PhotonPlayer[] otherPlayers
347     {
348         
get
349         {
350             
if (networkingPeer == null)
351                 
return new PhotonPlayer[0];
352
353             
return networkingPeer.mOtherPlayerListCopy;
354         }
355     }

356
357     ///
<summary>
358     ///
Read-only list of friends, their online status and the room they are in. Null until initialized by a FindFriends call.
359     ///
</summary>
360     ///
<remarks>
361     ///
Do not modify this list!
362     ///
It is internally handled by FindFriends and only available to read the values.
363     ///
The value of FriendsListAge tells you how old the data is in milliseconds.
364     ///
365     ///
Don't get this list more often than useful (> 10 seconds). In best case, keep the list you fetch really short.
366     ///
You could (e.g.) get the full list only once, then request a few updates only for friends who are online.
367     ///
After a while (e.g. 1 minute), you can get the full list again (to update online states).
368     ///
</remarks>
369     
public static List<FriendInfo> Friends { get; internal set; }
370
371     ///
<summary>
372     ///
Age of friend list info (in milliseconds). It's 0 until a friend list is fetched.
373     ///
</summary>
374     
public static int FriendsListAge
375     {
376         
get { return (networkingPeer != null) ? networkingPeer.FriendsListAge : 0; }
377     }

378
379     ///
<summary>
380     ///
While enabled (true), Instantiate uses PhotonNetwork.PrefabCache to keep game objects in memory (improving instantiation of the same prefab).
381     ///
</summary>
382     ///
<remarks>
383     ///
Setting UsePrefabCache to false during runtime will not clear PrefabCache but will ignore it right away.
384     ///
You could clean and modify the cache yourself. Read its comments.
385     ///
</remarks>
386     
public static bool UsePrefabCache = true;
387
388     ///
<summary>
389     ///
Keeps references to GameObjects for frequent instantiation (out of memory instead of loading the Resources).
390     ///
</summary>
391     ///
<remarks>
392     ///
You should be able to modify the cache anytime you like, except while Instantiate is used. Best do it only in the main-Thread.
393     ///
</remarks>
394     
public static Dictionary<string, GameObject> PrefabCache = new Dictionary<string, GameObject>();
395
396     ///
<summary>
397     ///
Offline mode can be set to re-use your multiplayer code in singleplayer game modes.
398     ///
When this is on PhotonNetwork will not create any connections and there is near to
399     ///
no overhead. Mostly usefull for reusing RPC's and PhotonNetwork.Instantiate
400     ///
</summary>
401     
public static bool offlineMode
402     {
403         
get
404         {
405             
return isOfflineMode;
406         }
407
408         
set
409         {
410             
if (value == isOfflineMode)
411             {
412                 
return;
413             }
414
415             
if (value && connected)
416             {
417                 Debug.LogError(
"Can't start OFFLINE mode while connected!");
418             }
419             
else
420             {
421                 
if (networkingPeer.PeerState != PeerStateValue.Disconnected)
422                 {
423                     networkingPeer.Disconnect();
// Cleanup (also calls OnLeftRoom to reset stuff)
424                 }
425                 isOfflineMode =
value;
426                 
if (isOfflineMode)
427                 {
428                     NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnConnectedToMaster);
429                     networkingPeer.ChangeLocalID(
1);
430                     networkingPeer.mMasterClient = player;
431                 }
432                 
else
433                 {
434                     offlineModeRoom =
null;
435                     networkingPeer.ChangeLocalID(-
1);
436                     networkingPeer.mMasterClient =
null;
437                 }
438             }
439         }
440     }
441
442     
private static bool isOfflineMode = false;
443     
private static Room offlineModeRoom = null;
444
445     
public static bool UseNameServer = true;
446
447     ///
<summary>
448     ///
If not null, this is the (exclusive) list of GameObjects that get called by PUN SendMonoMessage().
449     ///
</summary>
450     ///
<remarks>
451     ///
For all callbacks defined in PhotonNetworkingMessage, PUN will use SendMonoMessage and
452     ///
call FindObjectsOfType() to find all scripts and GameObjects that might want a callback by PUN.
453     ///
454     ///
PUN callbacks are not very frequent (in-game, property updates are most frequent) but
455     ///
FindObjectsOfType is time consuming and with a large number of GameObjects, performance might
456     ///
suffer.
457     ///
458     ///
Optionally, SendMonoMessageTargets can be used to supply a list of target GameObjects. This
459     ///
skips the FindObjectsOfType() but any GameObject that needs callbacks will have to Add itself
460     ///
to this list.
461     ///
462     ///
If null, the default behaviour is to do a SendMessage on each GameObject with a MonoBehaviour.
463     ///
</remarks>
464     
public static HashSet<GameObject> SendMonoMessageTargets;
465
466     
public static Type SendMonoMessageTargetType = typeof(MonoBehaviour);
467     
468
469     ///
<summary>
470     ///
Populates SendMonoMessageTargets with currently existing GameObjects that have a Component of type.
471     ///
</summary>
472     ///
<param name="type">If null, this will use SendMonoMessageTargets as component-type (MonoBehaviour by default).</param>
473     
public static void CacheSendMonoMessageTargets(Type type)
474     {
475         
if (type == null) type = SendMonoMessageTargetType;
476         PhotonNetwork.SendMonoMessageTargets = FindGameObjectsWithComponent(type);
477     }
478
479     
public static HashSet<GameObject> FindGameObjectsWithComponent(Type type)
480     {
481         HashSet<GameObject> objectsWithComponent =
new HashSet<GameObject>();
482
483         Component[] targetComponents = (Component[]) GameObject.FindObjectsOfType(type);
484         
for (int index = 0; index < targetComponents.Length; index++)
485         {
486             objectsWithComponent.Add(targetComponents[index].gameObject);
487         }
488
489         
return objectsWithComponent;
490     }

491
492     ///
<summary>
493     ///
The maximum number of players for a room. Better: Set it in CreateRoom.
494     ///
If no room is opened, this will return 0.
495     ///
</summary>
496     
[Obsolete("Used for compatibility with Unity networking only.")]
497     
public static int maxConnections
498     {
499         
get
500         {
501             
if (room == null)
502             {
503                 
return 0;
504             }
505
506             
return (int)room.maxPlayers;
507         }
508
509         
set
510         {
511             room.maxPlayers =
value;
512         }
513     }

514
515     ///
<summary>Defines if PUN automatically synchronizes the loaded level per room. Default: false / disabled.</summary>
516     ///
<remarks>
517     ///
If the MasterClient loads a level, all clients will load the new scene too.
518     ///
This also takes care of smooth loading of the game scene after joining a game.
519     ///
520     ///
In best case, use PhotonNetwork.LoadLevel on the Master Client to change levels.
521     ///
</remarks>
522     ///
<value>
523     ///
<c>true</c> if automatically sync scene; otherwise, <c>false</c>.
524     ///
</value>
525     
public static bool automaticallySyncScene
526     {
527         
get
528         {
529             
return _mAutomaticallySyncScene;
530         }
531         
set
532         {
533             _mAutomaticallySyncScene =
value;
534             
if (_mAutomaticallySyncScene && room != null)
535             {
536                 networkingPeer.LoadLevelIfSynced();
537             }
538         }
539     }
540
541     
private static bool _mAutomaticallySyncScene = false;
542
543     ///
<summary>
544     ///
This setting defines if players in a room should destroy a leaving player's instantiated GameObjects and PhotonViews.
545     ///
546     ///
When "this client" creates a room/game, autoCleanUpPlayerObjects is copied to that room's properties and used by all
547     ///
PUN clients in that room (no matter what their autoCleanUpPlayerObjects value is).
548     ///
549     ///
If room.AutoCleanUp is enabled in a room, the PUN clients will destroy a player's objects on leave.
550     ///
</summary>
551     ///
<remarks>
552     ///
When enabled, the server will clean RPCs, instantiated GameObjects and PhotonViews of the leaving player and joining
553     ///
players won't get those at anymore.
554     ///
555     ///
Once a room is created, this setting can't be changed anymore.
556     ///
557     ///
Enabled by default.
558     ///
</remarks>
559     
public static bool autoCleanUpPlayerObjects
560     {
561         
get
562         {
563             
return m_autoCleanUpPlayerObjects;
564         }
565         
set
566         {
567             
if (room != null)
568                 Debug.LogError(
"Setting autoCleanUpPlayerObjects while in a room is not supported.");
569             
else m_autoCleanUpPlayerObjects = value;
570         }
571     }
572
573     
private static bool m_autoCleanUpPlayerObjects = true;
574
575     ///
<summary>
576     ///
Defines if the PhotonNetwork should join the "lobby" when connected to the Master server.
577     ///
</summary>
578     ///
<remarks>
579     ///
If this is false, OnConnectedToMaster() will be called when connection to the Master is available.
580     ///
OnJoinedLobby() will NOT be called if this is false.
581     ///
582     ///
Enabled by default.
583     ///

584     ///
The room listing will not become available.
585     ///
Rooms can be created and joined (randomly) without joining the lobby (and getting sent the room list).
586     ///
</remarks>
587     
public static bool autoJoinLobby
588     {
589         
get
590         {
591             
return autoJoinLobbyField;
592         }
593         
set
594         {
595             autoJoinLobbyField =
value;
596         }
597     }

598
599     ///
<summary>
600     ///
Backing field.
601     ///
</summary>
602     
private static bool autoJoinLobbyField = true;
603
604     ///
<summary>True while this client is in a lobby.</summary>
605     ///
<remarks>
606     ///
You are automatically leaving any lobby when you join a room!
607     ///
Lobbies only exist on the Master Server (whereas rooms are handled by Game Servers).
608     ///
</remarks>
609     
public static bool insideLobby
610     {
611         
get
612         {
613             
return networkingPeer.insideLobby;
614         }
615     }

616
617     ///
<summary>
618     ///
The lobby that will be used when PUN joins a lobby or creates a game.
619     ///
</summary>
620     ///
<remarks>
621     ///
The default lobby uses an empty string as name.
622     ///
PUN will enter a lobby on the Master Server if autoJoinLobby is set to true.
623     ///
So when you connect or leave a room, PUN automatically gets you into a lobby again.
624     ///

625     ///
Check PhotonNetwork.insideLobby if the client is in a lobby.
626     ///
(@ref masterServerAndLobby)
627     ///
</remarks>
628     
public static TypedLobby lobby
629     {
630         
get { return networkingPeer.lobby; }
631         
set { networkingPeer.lobby = value; }
632     }

633
634     ///
<summary>
635     ///
Defines how many times per second PhotonNetwork should send a package. If you change
636     ///
this, do not forget to also change 'sendRateOnSerialize'.
637     ///
</summary>
638     ///
<remarks>
639     ///
Less packages are less overhead but more delay.
640     ///
Setting the sendRate to 50 will create up to 50 packages per second (which is a lot!).
641     ///
Keep your target platform in mind: mobile networks are slower and less reliable.
642     ///
</remarks>
643     
public static int sendRate
644     {
645         
get
646         {
647             
return 1000 / sendInterval;
648         }
649
650         
set
651         {
652             sendInterval =
1000 / value;
653             
if (photonMono != null)
654             {
655                 photonMono.updateInterval = sendInterval;
656             }
657
658             
if (value < sendRateOnSerialize)
659             {
660                 
// sendRateOnSerialize needs to be <= sendRate
661                 sendRateOnSerialize =
value;
662             }
663         }
664     }

665
666     ///
<summary>
667     ///
Defines how many times per second OnPhotonSerialize should be called on PhotonViews.
668     ///
</summary>
669     ///
<remarks>
670     ///
Choose this value in relation to 'sendRate'. OnPhotonSerialize will creart the commands to be put into packages.
671     ///
A lower rate takes up less performance but will cause more lag.
672     ///
</remarks>
673     
public static int sendRateOnSerialize
674     {
675         
get
676         {
677             
return 1000 / sendIntervalOnSerialize;
678         }
679
680         
set
681         {
682             
if (value > sendRate)
683             {
684                 Debug.LogError(
"Error, can not set the OnSerialize SendRate more often then the overall SendRate");
685                 
value = sendRate;
686             }
687
688             sendIntervalOnSerialize =
1000 / value;
689             
if (photonMono != null)
690             {
691                 photonMono.updateIntervalOnSerialize = sendIntervalOnSerialize;
692             }
693         }
694     }
695
696     
private static int sendInterval = 50; // in miliseconds.
697
698     
private static int sendIntervalOnSerialize = 100; // in miliseconds. I.e. 100 = 100ms which makes 10 times/second
699
700     ///
<summary>
701     ///
Can be used to pause dispatching of incoming evtents (RPCs, Instantiates and anything else incoming).
702     ///
</summary>
703     ///
<remarks>
704     ///
While IsMessageQueueRunning == false, the OnPhotonSerializeView calls are not done and nothing is sent by
705     ///
a client. Also, incoming messages will be queued until you re-activate the message queue.
706     ///
707     ///
This can be useful if you first want to load a level, then go on receiving data of PhotonViews and RPCs.
708     ///
The client will go on receiving and sending acknowledgements for incoming packages and your RPCs/Events.
709     ///
This adds "lag" and can cause issues when the pause is longer, as all incoming messages are just queued.
710     ///
</remarks>
711     
public static bool isMessageQueueRunning
712     {
713         
get
714         {
715             
return m_isMessageQueueRunning;
716         }
717
718         
set
719         {
720             
if (value) PhotonHandler.StartFallbackSendAckThread();
721             networkingPeer.IsSendingOnlyAcks = !
value;
722             m_isMessageQueueRunning =
value;
723         }
724     }

725
726     ///
<summary>Backup for property isMessageQueueRunning.</summary>
727     
private static bool m_isMessageQueueRunning = true;
728
729     ///
<summary>
730     ///
Used once per dispatch to limit unreliable commands per channel (so after a pause, many channels can still cause a lot of unreliable commands)
731     ///
</summary>
732     
public static int unreliableCommandsLimit
733     {
734         
get
735         {
736             
return networkingPeer.LimitOfUnreliableCommands;
737         }
738
739         
set
740         {
741             networkingPeer.LimitOfUnreliableCommands =
value;
742         }
743     }

744
745     ///
<summary>
746     ///
Photon network time, synched with the server
747     ///
</summary>
748     ///
<remarks>
749     ///
v1.3:
750     ///
This time reflects milliseconds since start of the server, cut down to 4 bytes.
751     ///
It will overflow every 49 days from a high value to 0. We do not (yet) compensate this overflow.
752     ///
Master- and Game-Server will have different time values.
753     ///
v1.10:
754     ///
Fixed issues with precision for high server-time values. This should update with 15ms precision by default.
755     ///
</remarks>
756     
public static double time
757     {
758         
get
759         {
760             
if (offlineMode)
761             {
762                 
return Time.time;
763             }
764             
else
765             {
766                 
return ((double)(uint)networkingPeer.ServerTimeInMilliSeconds) / 1000.0f;
767             }
768         }
769     }

770
771     ///
<summary>
772     ///
Are we the master client?
773     ///
</summary>
774     
public static bool isMasterClient
775     {
776         
get
777         {
778             
if (offlineMode)
779             {
780                 
return true;
781             }
782             
else
783             {
784                 
return networkingPeer.mMasterClient == networkingPeer.mLocalActor;
785             }
786         }
787     }

788
789     ///
<summary>Is true while being in a room (connectionStateDetailed == PeerState.Joined).</summary>
790     ///
<remarks>
791     ///
Many actions can only be executed in a room, like Instantiate or Leave, etc.
792     ///
You can join a room in offline mode, too.
793     ///
</remarks>
794     
public static bool inRoom
795     {
796         
get
797         {
798             
// in offline mode, you can be in a room too and connectionStateDetailed then returns Joined like on online mode!
799             
return connectionStateDetailed == PeerState.Joined;
800         }
801     }

802
803     ///
<summary>
804     ///
True if we are in a room (client) and NOT the room's masterclient
805     ///
</summary>
806     
public static bool isNonMasterClientInRoom
807     {
808         
get
809         {
810             
return !isMasterClient && room != null;
811         }
812     }

813
814     ///
<summary>
815     ///
The count of players currently looking for a room (available on MasterServer in 5sec intervals).
816     ///
</summary>
817     
public static int countOfPlayersOnMaster
818     {
819         
get
820         {
821             
return networkingPeer.mPlayersOnMasterCount;
822         }
823     }

824
825     ///
<summary>
826     ///
Count of users currently playing your app in some room (sent every 5sec by Master Server). Use playerList.Count to get the count of players in the room you're in!
827     ///
</summary>
828     
public static int countOfPlayersInRooms
829     {
830         
get
831         {
832             
return networkingPeer.mPlayersInRoomsCount;
833         }
834     }

835
836     ///
<summary>
837     ///
The count of players currently using this application (available on MasterServer in 5sec intervals).
838     ///
</summary>
839     
public static int countOfPlayers
840     {
841         
get
842         {
843             
return networkingPeer.mPlayersInRoomsCount + networkingPeer.mPlayersOnMasterCount;
844         }
845     }

846
847     ///
<summary>
848     ///
The count of rooms currently in use (available on MasterServer in 5sec intervals).
849     ///
</summary>
850     ///
<remarks>
851     ///
While inside the lobby you can also check the count of listed rooms as: PhotonNetwork.GetRoomList().Length.
852     ///
Since PUN v1.25 this is only based on the statistic event Photon sends (counting all rooms).
853     ///
</remarks>
854     
public static int countOfRooms
855     {
856         
get
857         {
858             
return networkingPeer.mGameCount;
859         }
860     }

861
862     ///
<summary>
863     ///
Enables or disables the collection of statistics about this client's traffic.
864     ///
</summary>
865     ///
<remarks>
866     ///
If you encounter issues with clients, the traffic stats are a good starting point to find solutions.
867     ///
Only with enabled stats, you can use GetVitalStats
868     ///
</remarks>
869     
public static bool NetworkStatisticsEnabled
870     {
871         
get
872         {
873             
return networkingPeer.TrafficStatsEnabled;
874         }
875
876         
set
877         {
878             networkingPeer.TrafficStatsEnabled =
value;
879         }
880     }

881
882     ///
<summary>
883     ///
Count of commands that got repeated (due to local repeat-timing before an ACK was received).
884     ///
</summary>
885     
public static int ResentReliableCommands
886     {
887         
get { return networkingPeer.ResentReliableCommands; }
888     }

889
890     ///
<summary>Crc checks can be useful to detect and avoid issues with broken datagrams. Can be enabled while not connected.</summary>
891     
public static bool CrcCheckEnabled
892     {
893         
get { return networkingPeer.CrcEnabled; }
894         
set
895         {
896             
if (!connected && !connecting)
897             {
898                 networkingPeer.CrcEnabled =
value;
899             }
900             
else
901             {
902                 Debug.Log(
"Can't change CrcCheckEnabled while being connected. CrcCheckEnabled stays " + networkingPeer.CrcEnabled);
903             }
904         }
905     }

906
907     ///
<summary>If CrcCheckEnabled, this counts the incoming packages that don't have a valid CRC checksum and got rejected.</summary>
908     
public static int PacketLossByCrcCheck
909     {
910         
get { return networkingPeer.PacketLossByCrc; }
911     }

912
913     ///
<summary>Defines the number of times a reliable message can be resent before not getting an ACK for it will trigger a disconnect. Default: 5.</summary>
914     ///
<remarks>Less resends mean quicker disconnects, while more can lead to much more lag without helping. Min: 3. Max: 10.</remarks>
915     
public static int MaxResendsBeforeDisconnect
916     {
917         
get { return networkingPeer.SentCountAllowance; }
918         
set
919         {
920             
if (value < 3) value = 3;
921             
if (value > 10) value = 10;
922             networkingPeer.SentCountAllowance =
value;
923         }
924     }

925
926     ///
<summary>The server this client is currently connected or connecting to.</summary>
927     
public static ServerConnection Server { get { return PhotonNetwork.networkingPeer.server; } }
928
929     ///
<summary>
930     ///
Defines the delegate usable in OnEventCall.
931     ///
</summary>
932     ///
<remarks>Any eventCode &lt; 200 will be forwarded to your delegate(s).</remarks>
933     ///
<param name="eventCode">The code assigend to the incoming event.</param>
934     ///
<param name="content">The content the sender put into the event.</param>
935     ///
<param name="senderId">The ID of the player who sent the event. It might be 0, if the "room" sent the event.</param>
936     
public delegate void EventCallback(byte eventCode, object content, int senderId);
937
938     ///
<summary>Register your RaiseEvent handling methods here by using "+=".</summary>
939     ///
<remarks>Any eventCode &lt; 200 will be forwarded to your delegate(s).</remarks>
940     ///
<see cref="RaiseEvent"/>
941     
public static EventCallback OnEventCall;
942
943
944     
internal static int lastUsedViewSubId = 0; // each player only needs to remember it's own (!) last used subId to speed up assignment
945     
internal static int lastUsedViewSubIdStatic = 0; // per room, the master is able to instantiate GOs. the subId for this must be unique too
946     
internal static List<int> manuallyAllocatedViewIds = new List<int>();
947
948     ///
<summary>
949     ///
Resets the traffic stats and re-enables them.
950     ///
</summary>
951     
public static void NetworkStatisticsReset()
952     {
953         networkingPeer.TrafficStatsReset();
954     }

955
956
957     ///
<summary>
958     ///
Only available when NetworkStatisticsEnabled was used to gather some stats.
959     ///
</summary>
960     ///
<returns>A string with vital networking statistics.</returns>
961     
public static string NetworkStatisticsToString()
962     {
963         
if (networkingPeer == null || offlineMode)
964         {
965             
return "Offline or in OfflineMode. No VitalStats available.";
966         }
967
968         
return networkingPeer.VitalStatsToString(false);
969     }

970
971     ///
<summary>
972     ///
Static constructor used for basic setup.
973     ///
</summary>
974     
static PhotonNetwork()
975     {
976         #
if UNITY_EDITOR
977         
if (!EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode)
978         {
979             
//Debug.Log(string.Format("PhotonNetwork.ctor() Not playing {0} {1}", UnityEditor.EditorApplication.isPlaying, UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode));
980             
return;
981         }
982
983         
// This can happen when you recompile a script IN play made
984         
// This helps to surpress some errors, but will not fix breaking
985         PhotonHandler[] photonHandlers = GameObject.FindObjectsOfType(
typeof(PhotonHandler)) as PhotonHandler[];
986         
if (photonHandlers != null && photonHandlers.Length > 0)
987         {
988             Debug.LogWarning(
"Unity recompiled. Connection gets closed and replaced. You can connect as 'new' client.");
989             
foreach (PhotonHandler photonHandler in photonHandlers)
990             {
991                 
//Debug.Log("Handler: " + photonHandler + " photonHandler.gameObject: " + photonHandler.gameObject);
992                 photonHandler.gameObject.hideFlags =
0;
993                 GameObject.DestroyImmediate(photonHandler.gameObject);
994                 Component.DestroyImmediate(photonHandler);
995             }
996         }
997         #endif
998
999         Application.runInBackground =
true;
1000
1001         
// Set up a MonoBehaviour to run Photon, and hide it
1002         GameObject photonGO =
new GameObject();
1003         photonMono = (PhotonHandler)photonGO.AddComponent<PhotonHandler>();
1004         photonGO.name =
"PhotonMono";
1005         photonGO.hideFlags = HideFlags.HideInHierarchy;
1006
1007
1008         
// Set up the NetworkingPeer and use protocol of PhotonServerSettings
1009         networkingPeer =
new NetworkingPeer(photonMono, string.Empty, PhotonNetwork.PhotonServerSettings.Protocol);
1010
1011
1012         
// Local player
1013         CustomTypes.Register();
1014     }

1015
1016     ///
<summary>
1017     ///
While offline, the network protocol can be switched (which affects the ports you can use to connect).
1018     ///
</summary>
1019     ///
<remarks>
1020     ///
When you switch the protocol, make sure to also switch the port for the master server. Default ports are:
1021     ///
TCP: 4530
1022     ///
UDP: 5055
1023     ///
1024     ///
This could look like this:<br/>
1025     ///
Connect(serverAddress, <udpport|tcpport>, appID, gameVersion)
1026     ///
1027     ///
Or when you use ConnectUsingSettings(), the PORT in the settings can be switched like so:<br/>
1028     ///
PhotonNetwork.PhotonServerSettings.ServerPort = 4530;
1029     ///
1030     ///
The current protocol can be read this way:<br/>
1031     ///
PhotonNetwork.networkingPeer.UsedProtocol
1032     ///
1033     ///
This does not work with the native socket plugin of PUN+ on mobile!
1034     ///
</remarks>
1035     ///
<param name="cp">Network protocol to use as low level connection. UDP is default. TCP is not available on all platforms (see remarks).</param>
1036     
public static void SwitchToProtocol(ConnectionProtocol cp)
1037     {
1038         
if (networkingPeer.UsedProtocol == cp)
1039         {
1040             
return;
1041         }
1042         
try
1043         {
1044             networkingPeer.Disconnect();
1045             networkingPeer.StopThread();
1046         }
1047         
catch
1048         {
1049
1050         }
1051
1052         
// set up a new NetworkingPeer
1053         NetworkingPeer newPeer =
new NetworkingPeer(photonMono, String.Empty, cp);
1054         newPeer.mAppVersion = networkingPeer.mAppVersion;
1055         newPeer.CustomAuthenticationValues = networkingPeer.CustomAuthenticationValues;
1056         newPeer.PlayerName= networkingPeer.PlayerName;
1057         newPeer.mLocalActor = networkingPeer.mLocalActor;
1058         newPeer.DebugOut = networkingPeer.DebugOut;
1059         newPeer.CrcEnabled = networkingPeer.CrcEnabled;
1060         newPeer.lobby = networkingPeer.lobby;
1061         newPeer.LimitOfUnreliableCommands = networkingPeer.LimitOfUnreliableCommands;
1062         newPeer.SentCountAllowance = networkingPeer.SentCountAllowance;
1063         newPeer.TrafficStatsEnabled = networkingPeer.TrafficStatsEnabled;
1064
1065         networkingPeer = newPeer;
1066         Debug.LogWarning(
"Protocol switched to: " + cp + ".");
1067     }

1068
1069     ///
<summary>
1070     ///
Internally used by Editor scripts, called on Hierarchy change (includes scene save) to remove surplus hidden PhotonHandlers.
1071     ///
</summary>
1072     
public static void InternalCleanPhotonMonoFromSceneIfStuck()
1073     {
1074         PhotonHandler[] photonHandlers = GameObject.FindObjectsOfType(
typeof(PhotonHandler)) as PhotonHandler[];
1075         
if (photonHandlers != null && photonHandlers.Length > 0)
1076         {
1077             Debug.Log(
"Cleaning up hidden PhotonHandler instances in scene. Please save it. This is not an issue.");
1078             
foreach (PhotonHandler photonHandler in photonHandlers)
1079             {
1080                 
// Debug.Log("Removing Handler: " + photonHandler + " photonHandler.gameObject: " + photonHandler.gameObject);
1081                 photonHandler.gameObject.hideFlags =
0;
1082
1083                 
if (photonHandler.gameObject != null && photonHandler.gameObject.name == "PhotonMono")
1084                 {
1085                     GameObject.DestroyImmediate(photonHandler.gameObject);
1086                 }
1087
1088                 Component.DestroyImmediate(photonHandler);
1089             }
1090         }
1091     }

1092
1093
1094     ///
<summary>Connect to Photon as configured in the editor (saved in PhotonServerSettings file).</summary>
1095     ///
<remarks>
1096     ///
This method will disable offlineMode (which won't destroy any instantiated GOs) and it
1097     ///
will set isMessageQueueRunning to true.
1098     ///
1099     ///
Your server configuration is created by the PUN Wizard and contains the AppId and
1100     ///
region for Photon Cloud games and the server address if you host Photon yourself.
1101     ///
These settings usually don't change often.
1102     ///
1103     ///
To ignore the config file and connect anywhere call: PhotonNetwork.ConnectToMaster.
1104     ///
1105     ///
To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard).
1106     ///
https://cloud.exitgames.com/dashboard
1107     ///
1108     ///
Connecting to the Photon Cloud might fail due to:
1109     ///
- Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value)
1110     ///
- Network issues (calls: OnFailedToConnectToPhoton())
1111     ///
- Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion)
1112     ///
- Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached())
1113     ///
1114     ///
More about the connection limitations:
1115     ///
http://doc.exitgames.com/photon-cloud
1116     ///
</remarks>
1117     ///
<param name="gameVersion">This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).</param>
1118     
public static bool ConnectUsingSettings(string gameVersion)
1119     {
1120         
if (PhotonServerSettings == null)
1121         {
1122             Debug.LogError(
"Can't connect: Loading settings failed. ServerSettings asset must be in any 'Resources' folder as: " + serverSettingsAssetFile);
1123             
return false;
1124         }
1125
1126         SwitchToProtocol(PhotonServerSettings.Protocol);
1127         networkingPeer.SetApp(PhotonServerSettings.AppID, gameVersion);
1128
1129         
if (PhotonServerSettings.HostType == ServerSettings.HostingOption.OfflineMode)
1130         {
1131             offlineMode =
true;
1132             
return true;
1133         }
1134
1135         
if (offlineMode)
1136         {
1137             
// someone can set offlineMode in code and then call ConnectUsingSettings() with non-offline settings. Warning for that case:
1138             Debug.LogWarning(
"ConnectUsingSettings() disabled the offline mode. No longer offline.");
1139         }
1140
1141         offlineMode =
false; // Cleanup offline mode
1142         isMessageQueueRunning =
true;
1143         networkingPeer.IsInitialConnect =
true;
1144
1145         
if (PhotonServerSettings.HostType == ServerSettings.HostingOption.SelfHosted)
1146         {
1147             networkingPeer.IsUsingNameServer =
false;
1148             networkingPeer.MasterServerAddress = (PhotonServerSettings.ServerPort ==
0) ? PhotonServerSettings.ServerAddress : PhotonServerSettings.ServerAddress + ":" + PhotonServerSettings.ServerPort;
1149
1150             
return networkingPeer.Connect(networkingPeer.MasterServerAddress, ServerConnection.MasterServer);
1151         }
1152
1153         
if (PhotonServerSettings.HostType == ServerSettings.HostingOption.BestRegion)
1154         {
1155             
return ConnectToBestCloudServer(gameVersion);
1156         }
1157
1158         
return networkingPeer.ConnectToRegionMaster(PhotonServerSettings.PreferredRegion);
1159     }

1160
1161     ///
<summary>Connect to a Photon Master Server by address, port, appID and game(client) version.</summary>
1162     ///
<remarks>
1163     ///
To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard).
1164     ///
https://cloud.exitgames.com/dashboard
1165     ///
1166     ///
Connecting to the Photon Cloud might fail due to:
1167     ///
- Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value)
1168     ///
- Network issues (calls: OnFailedToConnectToPhoton())
1169     ///
- Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion)
1170     ///
- Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached())
1171     ///
1172     ///
More about the connection limitations:
1173     ///
http://doc.exitgames.com/photon-cloud/
1174     ///
</remarks>
1175     ///
<param name="masterServerAddress">The server's address (either your own or Photon Cloud address).</param>
1176     ///
<param name="port">The server's port to connect to.</param>
1177     ///
<param name="appID">Your application ID (Photon Cloud provides you with a GUID for your game).</param>
1178     ///
<param name="gameVersion">This client's version number. Users are separated by gameversion (which allows you to make breaking changes).</param>
1179     
public static bool ConnectToMaster(string masterServerAddress, int port, string appID, string gameVersion)
1180     {
1181         
if (networkingPeer.PeerState != PeerStateValue.Disconnected)
1182         {
1183             Debug.LogWarning(
"ConnectToMaster() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState);
1184             
return false;
1185         }
1186
1187         
if (offlineMode)
1188         {
1189             offlineMode =
false; // Cleanup offline mode
1190             Debug.LogWarning(
"ConnectToMaster() disabled the offline mode. No longer offline.");
1191         }
1192
1193         
if (!isMessageQueueRunning)
1194         {
1195             isMessageQueueRunning =
true;
1196             Debug.LogWarning(
"ConnectToMaster() enabled isMessageQueueRunning. Needs to be able to dispatch incoming messages.");
1197         }
1198
1199         networkingPeer.SetApp(appID, gameVersion);
1200         networkingPeer.IsUsingNameServer =
false;
1201         networkingPeer.IsInitialConnect =
true;
1202         networkingPeer.MasterServerAddress = (port ==
0) ? masterServerAddress : masterServerAddress + ":" + port;
1203
1204         
return networkingPeer.Connect(networkingPeer.MasterServerAddress, ServerConnection.MasterServer);
1205     }

1206
1207
1208     ///
<summary>
1209     ///
Connect to the Photon Cloud region with the lowest ping (on platforms that support Unity's Ping).
1210     ///
</summary>
1211     ///
<remarks>
1212     ///
Will save the result of pinging all cloud servers in PlayerPrefs. Calling this the first time can take +-2 seconds.
1213     ///
The ping result can be overridden via PhotonNetwork.OverrideBestCloudServer(..)
1214     ///
This call can take up to 2 seconds if it is the first time you are using this, all cloud servers will be pinged to check for the best region.
1215     ///
1216     ///
The PUN Setup Wizard stores your appID in a settings file and applies a server address/port.
1217     ///
To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard).
1218     ///
https://cloud.exitgames.com/dashboard
1219     ///
1220     ///
Connecting to the Photon Cloud might fail due to:
1221     ///
- Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value)
1222     ///
- Network issues (calls: OnFailedToConnectToPhoton())
1223     ///
- Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion)
1224     ///
- Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached())
1225     ///
1226     ///
More about the connection limitations:
1227     ///
http://doc.exitgames.com/photon-cloud
1228     ///
</remarks>
1229     ///
<param name="gameVersion">This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).</param>
1230     ///
<returns>If this client is going to connect to cloud server based on ping. Even if true, this does not guarantee a connection but the attempt is being made.</returns>
1231     
public static bool ConnectToBestCloudServer(string gameVersion)
1232     {
1233         
if (PhotonServerSettings == null)
1234         {
1235             Debug.LogError(
"Can't connect: Loading settings failed. ServerSettings asset must be in any 'Resources' folder as: " + PhotonNetwork.serverSettingsAssetFile);
1236             
return false;
1237         }
1238
1239         
if (PhotonServerSettings.HostType == ServerSettings.HostingOption.OfflineMode)
1240         {
1241             
return PhotonNetwork.ConnectUsingSettings(gameVersion);
1242         }
1243
1244         networkingPeer.IsInitialConnect =
true;
1245         networkingPeer.SetApp(PhotonServerSettings.AppID, gameVersion);
1246
1247         CloudRegionCode bestFromPrefs = PhotonHandler.BestRegionCodeInPreferences;
1248         
if (bestFromPrefs != CloudRegionCode.none)
1249         {
1250             Debug.Log(
"Best region found in PlayerPrefs. Connecting to: " + bestFromPrefs);
1251             
return networkingPeer.ConnectToRegionMaster(bestFromPrefs);
1252         }
1253
1254         
bool couldConnect = PhotonNetwork.networkingPeer.ConnectToNameServer();
1255         
return couldConnect;
1256     }

1257
1258     ///
<summary>Overwrites the region that is used for ConnectToBestCloudServer(string gameVersion).</summary>
1259     ///
<remarks>
1260     ///
This will overwrite the result of pinging all cloud servers.
1261     ///
Use this to allow your users to save a manually selected region in the prefs.
1262     ///
</remarks>
1263     
public static void OverrideBestCloudServer(CloudRegionCode region)
1264     {
1265         PhotonHandler.BestRegionCodeInPreferences = region;
1266     }

1267
1268     ///
<summary>Pings all cloud servers again to find the one with best ping (currently).</summary>
1269     
public static void RefreshCloudServerRating()
1270     {
1271         
throw new NotImplementedException("not available at the moment");
1272     }

1273
1274
1275     ///
<summary>
1276     ///
Makes this client disconnect from the photon server, a process that leaves any room and calls OnDisconnectedFromPhoton on completion.
1277     ///
</summary>
1278     ///
<remarks>
1279     ///
When you disconnect, the client will send a "disconnecting" message to the server. This speeds up leave/disconnect
1280     ///
messages for players in the same room as you (otherwise the server would timeout this client's connection).
1281     ///
When used in offlineMode, the state-change and event-call OnDisconnectedFromPhoton are immediate.
1282     ///
Offline mode is set to false as well.
1283     ///
Once disconnected, the client can connect again. Use ConnectUsingSettings.
1284     ///
</remarks>
1285     
public static void Disconnect()
1286     {
1287         
if (offlineMode)
1288         {
1289             offlineMode =
false;
1290             offlineModeRoom =
null;
1291             networkingPeer.State = PeerState.Disconnecting;
1292             networkingPeer.OnStatusChanged(StatusCode.Disconnect);
1293             
return;
1294         }
1295
1296         
if (networkingPeer == null)
1297         {
1298             
return; // Surpress error when quitting playmode in the editor
1299         }
1300
1301         networkingPeer.Disconnect();
1302     }

1303
1304     ///
<summary>
1305     ///
Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting.
1306     ///
</summary>
1307     
[Obsolete("Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting.")]
1308     
public static void InitializeSecurity()
1309     {
1310         
return;
1311     }

1312
1313     ///
<summary>
1314     ///
Requests the rooms and online status for a list of friends and saves the result in PhotonNetwork.Friends.
1315     ///
</summary>
1316     ///
<remarks>
1317     ///
Works only on Master Server to find the rooms played by a selected list of users.
1318     ///
1319     ///
The result will be stored in PhotonNetwork.Friends when available.
1320     ///
That list is initialized on first use of OpFindFriends (before that, it is null).
1321     ///
To refresh the list, call FindFriends again (in 5 seconds or 10 or 20).
1322     ///
1323     ///
Users identify themselves by setting a unique username via PhotonNetwork.playerName
1324     ///
or by PhotonNetwork.AuthValues. The user id set in AuthValues overrides the playerName,
1325     ///
so make sure you know the ID your friends use to authenticate.
1326     ///
The AuthValues are sent in OpAuthenticate when you connect, so the AuthValues must be
1327     ///
set before you connect!
1328     ///

1329     ///
Note: Changing a player's name doesn't make sense when using a friend list.
1330     ///
1331     ///
The list of friends must be fetched from some other source (not provided by Photon).
1332     ///
1333     ///
1334     ///
Internal:
1335     ///
The server response includes 2 arrays of info (each index matching a friend from the request):
1336     ///
ParameterCode.FindFriendsResponseOnlineList = bool[] of online states
1337     ///
ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room)
1338     ///
</remarks>
1339     ///
<param name="friendsToFind">Array of friend (make sure to use unique playerName or AuthValues).</param>
1340     ///
<returns>If the operation could be sent (requires connection, only one request is allowed at any time). Always false in offline mode.</returns>
1341     
public static bool FindFriends(string[] friendsToFind)
1342     {
1343         
if (networkingPeer == null || isOfflineMode)
1344         {
1345             
return false;
1346         }
1347
1348         
return networkingPeer.OpFindFriends(friendsToFind);
1349     }

1350
1351     ///
<summary>
1352     ///
Creates a room with given name but fails if this room is existing already.
1353     ///
</summary>
1354     ///
<remarks>
1355     ///
If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
1356     ///
1357     ///
The created room is automatically placed in the currently used lobby or the default-lobby if you didn't explicitly join one.
1358     ///
1359     ///
Call this only on the master server.
1360     ///
Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
1361     ///
to switch to the assigned game server and roomName
1362     ///
</remarks>
1363     ///
<param name="roomName">Unique name of the room to create. Pass null or "" to make the server generate a name.</param>
1364     ///
<param name="isVisible">Shows (or hides) this room from the lobby's listing of rooms.</param>
1365     ///
<param name="isOpen">Allows (or disallows) others to join this room.</param>
1366     ///
<param name="maxPlayers">Max number of players that can join the room.</param>
1367     
[Obsolete("Use overload with RoomOptions and TypedLobby parameters.")]
1368     
public static bool CreateRoom(string roomName, bool isVisible, bool isOpen, int maxPlayers)
1369     {
1370         RoomOptions roomOptions =
new RoomOptions();
1371         roomOptions.isVisible = isVisible;
1372         roomOptions.isOpen = isOpen;
1373         roomOptions.maxPlayers = maxPlayers;
1374
1375         
return CreateRoom(roomName, roomOptions, null);
1376     }

1377
1378     ///
<summary>
1379     ///
Creates a room with given name but fails if this room is existing already.
1380     ///
</summary>
1381     ///
<remarks>
1382     ///
If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
1383     ///
1384     ///
The created room is automatically placed in the currently used lobby or the default-lobby if you didn't explicitly join one.
1385     ///
1386     ///
Call this only on the master server.
1387     ///
Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
1388     ///
to switch to the assigned game server and roomName.
1389     ///
1390     ///
PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room.
1391     ///
</remarks>
1392     ///
<param name="roomName">Unique name of the room to create. Pass null or "" to make the server generate a name.</param>
1393     ///
<param name="isVisible">Shows (or hides) this room from the lobby's listing of rooms.</param>
1394     ///
<param name="isOpen">Allows (or disallows) others to join this room.</param>
1395     ///
<param name="maxPlayers">Max number of players that can join the room.</param>
1396     ///
<param name="customRoomProperties">Custom properties of the new room (set on create, so they are immediately available).</param>
1397     ///
<param name="propsToListInLobby">Array of custom-property-names that should be forwarded to the lobby (include only the useful ones).</param>
1398     
[Obsolete("Use overload with RoomOptions and TypedLobby parameters.")]
1399     
public static bool CreateRoom(string roomName, bool isVisible, bool isOpen, int maxPlayers, Hashtable customRoomProperties, string[] propsToListInLobby)
1400     {
1401         RoomOptions roomOptions =
new RoomOptions();
1402         roomOptions.isVisible = isVisible;
1403         roomOptions.isOpen = isOpen;
1404         roomOptions.maxPlayers = maxPlayers;
1405         roomOptions.customRoomProperties = customRoomProperties;
1406         roomOptions.customRoomPropertiesForLobby = propsToListInLobby;
1407
1408         
return CreateRoom(roomName, roomOptions, null);
1409     }

1410
1411
1412     ///
<summary>
1413     ///
Creates a room with given name but fails if this room(name) is existing already. Creates random name for roomName null.
1414     ///
</summary>
1415     ///
<remarks>
1416     ///
If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
1417     ///
1418     ///
The created room is automatically placed in the currently used lobby (if any) or the default-lobby if you didn't explicitly join one.
1419     ///
1420     ///
Call this only on the master server.
1421     ///
Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
1422     ///
to switch to the assigned game server and roomName.
1423     ///
1424     ///
PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room.
1425     ///
</remarks>
1426     ///
<param name="roomName">Unique name of the room to create.</param>
1427     
public static bool CreateRoom(string roomName)
1428     {
1429         
return CreateRoom(roomName, null, null);
1430     }

1431
1432     ///
<summary>
1433     ///
Creates a room but fails if this room is existing already. Can only be called on Master Server.
1434     ///
</summary>
1435     ///
<remarks>
1436     ///
When successful, this calls the callbacks OnCreatedRoom and OnJoinedRoom (the latter, cause you join as first player).
1437     ///
If the room can't be created (because it exists already), OnPhotonCreateRoomFailed gets called.
1438     ///
1439     ///
If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
1440     ///
1441     ///
Rooms can be created in any number of lobbies. Those don't have to exist before you create a room in them (they get
1442     ///
auto-created on demand). Lobbies can be useful to split room lists on the server-side already. That can help keep the room
1443     ///
lists short and manageable.
1444     ///
If you set a typedLobby parameter, the room will be created in that lobby (no matter if you are active in any).
1445     ///
If you don't set a typedLobby, the room is automatically placed in the currently active lobby (if any) or the
1446     ///
default-lobby.
1447     ///
1448     ///
Call this only on the master server.
1449     ///
Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
1450     ///
to switch to the assigned game server and roomName.
1451     ///
1452     ///
PhotonNetwork.autoCleanUpPlayerObjects will become this room's autoCleanUp property and that's used by all clients that join this room.
1453     ///
</remarks>
1454     ///
<param name="roomName">Unique name of the room to create. Pass null or "" to make the server generate a name.</param>
1455     ///
<param name="roomOptions">Common options for the room like maxPlayers, initial custom room properties and similar. See RoomOptions type..</param>
1456     ///
<param name="typedLobby">If null, the room is automatically created in the currently used lobby (which is "default" when you didn't join one explicitly).</param>
1457     
public static bool CreateRoom(string roomName, RoomOptions roomOptions, TypedLobby typedLobby)
1458     {
1459         
if (offlineMode)
1460         {
1461             
if (offlineModeRoom != null)
1462             {
1463                 Debug.LogError(
"CreateRoom failed. In offline mode you still have to leave a room to enter another.");
1464                 
return false;
1465             }
1466
1467             offlineModeRoom =
new Room(roomName, roomOptions);
1468             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom);
1469             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
1470             
return true;
1471         }
1472
1473
1474         
if (networkingPeer.server != ServerConnection.MasterServer || !connectedAndReady)
1475         {
1476             Debug.LogError(
"CreateRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster.");
1477             
return false;
1478         }
1479
1480         
return networkingPeer.OpCreateGame(roomName, roomOptions, typedLobby);
1481     }

1482
1483
1484     ///
<summary>Join room by roomName with an option to create it on the fly if not existing.</summary>
1485     ///
<remarks>
1486     ///
Join will try to enter a room by roomName. If this room is full or closed, this will fail.
1487     ///
If the room is not existing, JoinRoom will also fail by default.
1488     ///
1489     ///
You can set createIfNotExists to true to make the server create the room if required.
1490     ///
This makes it easier for groups of players to get into the same room. Once the group
1491     ///
exchanged a roomName, any player can try to join or create the room in one step -
1492     ///
it doesn't matter who's first.
1493     ///
1494     ///
OnJoinedRoom() gets called if the room existed and was joined,
1495     ///
OnCreatedRoom() gets called if the room didn't exist and this client created it.
1496     ///
OnPhotonJoinRoomFailed() gets called if the room couldn't be joined or created.
1497     ///
Implement either in any script in the scene to react to joining/creating a room.
1498     ///
1499     ///
To join a room from the lobby's listing, use RoomInfo.name as roomName here.
1500     ///
1501     ///
In OfflineMode, this always "finds" and joins a room.
1502     ///
</remarks>
1503     ///
1504     ///
<see cref="PhotonNetworkingMessage.OnPhotonJoinRoomFailed"/>
1505     ///
<see cref="PhotonNetworkingMessage.OnJoinedRoom"/>
1506     ///
1507     ///
<param name="roomName">Unique name of the room to join (or create if createIfNotExists is true).</param>
1508     ///
<param name="createIfNotExists">If true, the server will attempt to create a room, making the success callback OnCreatedRoom().</param>
1509     
[Obsolete("Use overload with roomOptions and TypedLobby parameter.")]
1510     
public static bool JoinRoom(string roomName, bool createIfNotExists)
1511     {
1512         
if (connectionStateDetailed == PeerState.Joining || connectionStateDetailed == PeerState.Joined || connectionStateDetailed == PeerState.ConnectedToGameserver)
1513         {
1514             Debug.LogError(
"JoinRoom aborted: You can only join a room while not currently connected/connecting to a room.");
1515         }
1516         
else if (room != null)
1517         {
1518             Debug.LogError(
"JoinRoom aborted: You are already in a room!");
1519         }
1520         
else if (roomName == string.Empty)
1521         {
1522             Debug.LogError(
"JoinRoom aborted: You must specifiy a room name!");
1523         }
1524         
else
1525         {
1526             
if (offlineMode)
1527             {
1528                 offlineModeRoom =
new Room(roomName, null);
1529                 NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
1530                 
return true;
1531             }
1532             
else
1533             {
1534                 
return networkingPeer.OpJoinRoom(roomName, null, null, createIfNotExists);
1535             }
1536         }
1537
1538         
return false; // offline and OpJoin both return but the error-cases don't
1539     }

1540
1541
1542     ///
<summary>Join room by roomname and on success calls OnJoinedRoom(). This is not affected by lobbies.</summary>
1543     ///
<remarks>
1544     ///
On success, the method OnJoinedRoom() is called on any script. You can implement it to react to joining a room.
1545     ///
1546     ///
JoinRoom fails if the room is either full or no longer available (it might become empty while you attempt to join).
1547     ///
Implement OnPhotonJoinRoomFailed() to get a callback in error case.
1548     ///
1549     ///
To join a room from the lobby's listing, use RoomInfo.name as roomName here.
1550     ///
Despite using multiple lobbies, a roomName is always "global" for your application and so you don't
1551     ///
have to specify which lobby it's in. The Master Server will find the room.
1552     ///
In the Photon Cloud, an application is defined by AppId, Game- and PUN-version.
1553     ///
</remarks>
1554     ///
<see cref="PhotonNetworkingMessage.OnPhotonJoinRoomFailed"/>
1555     ///
<see cref="PhotonNetworkingMessage.OnJoinedRoom"/>
1556     ///
<param name="roomName">Unique name of the room to join.</param>
1557     
public static bool JoinRoom(string roomName)
1558     {
1559         
if (offlineMode)
1560         {
1561             
if (offlineModeRoom != null)
1562             {
1563                 Debug.LogError(
"JoinRoom failed. In offline mode you still have to leave a room to enter another.");
1564                 
return false;
1565             }
1566
1567             offlineModeRoom =
new Room(roomName, null);
1568             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
1569             
return true;
1570         }
1571
1572
1573         
if (networkingPeer.server != ServerConnection.MasterServer || !connectedAndReady)
1574         {
1575             Debug.LogError(
"JoinRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster.");
1576             
return false;
1577         }
1578
1579         
if (string.IsNullOrEmpty(roomName))
1580         {
1581             Debug.LogError(
"JoinRoom failed. A roomname is required. If you don't know one, how will you join?");
1582             
return false;
1583         }
1584
1585         
return networkingPeer.OpJoinRoom(roomName, null, null, false);
1586     }

1587
1588
1589     ///
<summary>Lets you either join a named room or create it on the fly - you don't have to know if someone created the room already.</summary>
1590     ///
<remarks>
1591     ///
This makes it easier for groups of players to get into the same room. Once the group
1592     ///
exchanged a roomName, any player can call JoinOrCreateRoom and it doesn't matter who
1593     ///
actually joins or creates the room.
1594     ///
1595     ///
The parameters roomOptions and typedLobby are only used when the room actually gets created by this client.
1596     ///
You know if this client created a room, if you get a callback OnCreatedRoom (before OnJoinedRoom gets called as well).
1597     ///
</remarks>
1598     ///
<param name="roomName">Name of the room to join. Must be non null.</param>
1599     ///
<param name="roomOptions">Options for the room, in case it does not exist yet. Else these values are ignored.</param>
1600     ///
<param name="typedLobby">Lobby you want a new room to be listed in. Ignored if the room was existing and got joined.</param>
1601     ///
<returns>If the operation got queued and will be sent.</returns>
1602     
public static bool JoinOrCreateRoom(string roomName, RoomOptions roomOptions, TypedLobby typedLobby)
1603     {
1604         
if (offlineMode)
1605         {
1606             
if (offlineModeRoom != null)
1607             {
1608                 Debug.LogError(
"JoinOrCreateRoom failed. In offline mode you still have to leave a room to enter another.");
1609                 
return false;
1610             }
1611
1612             offlineModeRoom =
new Room(roomName, roomOptions);
1613             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom);
// in offline mode you create, too for JoinOrCreateRoom
1614             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
1615             
return true;
1616         }
1617
1618
1619         
if (networkingPeer.server != ServerConnection.MasterServer || !connectedAndReady)
1620         {
1621             Debug.LogError(
"JoinOrCreateRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster.");
1622             
return false;
1623         }
1624
1625         
if (string.IsNullOrEmpty(roomName))
1626         {
1627             Debug.LogError(
"JoinOrCreateRoom failed. A roomname is required. If you don't know one, how will you join?");
1628             
return false;
1629         }
1630
1631         
return networkingPeer.OpJoinRoom(roomName, roomOptions, typedLobby, true);
1632     }

1633
1634     ///
<summary>
1635     ///
Joins any available room of the currently used lobby and fails if none is available.
1636     ///
</summary>
1637     ///
<remarks>
1638     ///
Rooms can be created in arbitrary lobbies which get created on demand.
1639     ///
You can join rooms from any lobby without actually joining the lobby.
1640     ///
Use the JoinRandomRoom overload with TypedLobby parameter.
1641     ///
1642     ///
This method will only match rooms attached to one lobby! If you use many lobbies, you
1643     ///
might have to repeat JoinRandomRoom, to find some fitting room.
1644     ///
This method looks up a room in the currently active lobby or (if no lobby is joined)
1645     ///
in the default lobby.
1646     ///
1647     ///
If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).
1648     ///
Alternatively, try again in a moment.
1649     ///
</remarks>
1650     
public static bool JoinRandomRoom()
1651     {
1652         
return JoinRandomRoom(null, 0, MatchmakingMode.FillRoom, null, null);
1653     }

1654
1655     ///
<summary>
1656     ///
Attempts to join an open room with fitting, custom properties but fails if none is currently available.
1657     ///
</summary>
1658     ///
<remarks>
1659     ///
Rooms can be created in arbitrary lobbies which get created on demand.
1660     ///
You can join rooms from any lobby without actually joining the lobby.
1661     ///
Use the JoinRandomRoom overload with TypedLobby parameter.
1662     ///
1663     ///
This method will only match rooms attached to one lobby! If you use many lobbies, you
1664     ///
might have to repeat JoinRandomRoom, to find some fitting room.
1665     ///
This method looks up a room in the currently active lobby or (if no lobby is joined)
1666     ///
in the default lobby.
1667     ///
1668     ///
If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).
1669     ///
Alternatively, try again in a moment.
1670     ///
</remarks>
1671     ///
<param name="expectedCustomRoomProperties">Filters for rooms that match these custom properties (string keys and values). To ignore, pass null.</param>
1672     ///
<param name="expectedMaxPlayers">Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.</param>
1673     
public static bool JoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers)
1674     {
1675         
return JoinRandomRoom(expectedCustomRoomProperties, expectedMaxPlayers, MatchmakingMode.FillRoom, null, null);
1676     }

1677
1678     ///
<summary>
1679     ///
Attempts to join an open room with fitting, custom properties but fails if none is currently available.
1680     ///
</summary>
1681     ///
<remarks>
1682     ///
Rooms can be created in arbitrary lobbies which get created on demand.
1683     ///
You can join rooms from any lobby without actually joining the lobby with this overload.
1684     ///
1685     ///
This method will only match rooms attached to one lobby! If you use many lobbies, you
1686     ///
might have to repeat JoinRandomRoom, to find some fitting room.
1687     ///
This method looks up a room in the specified lobby or the currently active lobby (if none specified)
1688     ///
or in the default lobby (if none active).
1689     ///
1690     ///
If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).
1691     ///
Alternatively, try again in a moment.
1692     ///
1693     ///
In offlineMode, a room will be created but no properties will be set and all parameters of this
1694     ///
JoinRandomRoom call are ignored. The event/callback OnJoinedRoom gets called (see enum PhotonNetworkingMessage).
1695     ///
</remarks>
1696     ///
<param name="expectedCustomRoomProperties">Filters for rooms that match these custom properties (string keys and values). To ignore, pass null.</param>
1697     ///
<param name="expectedMaxPlayers">Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.</param>
1698     ///
<param name="matchingType">Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options.</param>
1699     ///
<param name="typedLobby">The lobby in which you want to lookup a room. Pass null, to use the default lobby. This does not join that lobby and neither sets the lobby property.</param>
1700     ///
<param name="sqlLobbyFilter">A filter-string for SQL-typed lobbies.</param>
1701     
public static bool JoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers, MatchmakingMode matchingType, TypedLobby typedLobby, string sqlLobbyFilter)
1702     {
1703         
if (offlineMode)
1704         {
1705             
if (offlineModeRoom != null)
1706             {
1707                 Debug.LogError(
"JoinRandomRoom failed. In offline mode you still have to leave a room to enter another.");
1708                 
return false;
1709             }
1710
1711             offlineModeRoom =
new Room("offline room", null);
1712             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
1713             
return true;
1714         }
1715
1716
1717         
if (networkingPeer.server != ServerConnection.MasterServer || !connectedAndReady)
1718         {
1719             Debug.LogError(
"JoinRandomRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster.");
1720             
return false;
1721         }
1722
1723         
return networkingPeer.OpJoinRandomRoom(expectedCustomRoomProperties, expectedMaxPlayers, null, matchingType, typedLobby, sqlLobbyFilter);
1724     }

1725
1726     ///
<summary>On MasterServer this joins the default lobby which list rooms currently in use.</summary>
1727     ///
<remarks>
1728     ///
The room list is sent and refreshed by the server. You can access this cached list by
1729     ///
PhotonNetwork.GetRoomList().
1730     ///
1731     ///
Per room you should check if it's full or not before joining. Photon also lists rooms that are
1732     ///
full, unless you close and hide them (room.open = false and room.visible = false).
1733     ///
1734     ///
In best case, you make your clients join random games, as described here:
1735     ///
http://doc.exitgames.com/en/realtime/current/reference/matchmaking-and-lobby
1736     ///
1737     ///
1738     ///
You can show your current players and room count without joining a lobby (but you must
1739     ///
be on the master server). Use: countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and
1740     ///
countOfRooms.
1741     ///
1742     ///
You can use more than one lobby to keep the room lists shorter. See JoinLobby(TypedLobby lobby).
1743     ///
When creating new rooms, they will be "attached" to the currently used lobby or the default lobby.
1744     ///
1745     ///
You can use JoinRandomRoom without being in a lobby!
1746     ///
Set autoJoinLobby = false before you connect, to not join a lobby. In that case, the
1747     ///
connect-workflow will call OnConnectedToMaster (if you implement it) when it's done.
1748     ///
</remarks>
1749     
public static bool JoinLobby()
1750     {
1751         
return JoinLobby(null);
1752     }

1753
1754     ///
<summary>On a Master Server you can join a lobby to get lists of available rooms.</summary>
1755     ///
<remarks>
1756     ///
The room list is sent and refreshed by the server. You can access this cached list by
1757     ///
PhotonNetwork.GetRoomList().
1758     ///
1759     ///
Any client can "make up" any lobby on the fly. Splitting rooms into multiple lobbies will
1760     ///
keep each list shorter. However, having too many lists might ruin the matchmaking experience.
1761     ///
1762     ///
In best case, you create a limited number of lobbies. For example, create a lobby per
1763     ///
game-mode: "koth" for king of the hill and "ffa" for free for all, etc.
1764     ///
1765     ///
There is no listing of lobbies at the moment.
1766     ///
1767     ///
Sql-typed lobbies offer a different filtering model for random matchmaking. This might be more
1768     ///
suited for skillbased-games. However, you will also need to follow the conventions for naming
1769     ///
filterable properties in sql-lobbies! Both is explained in the matchmaking doc linked below.
1770     ///
1771     ///
In best case, you make your clients join random games, as described here:
1772     ///
http://confluence.exitgames.com/display/PTN/Op+JoinRandomGame
1773     ///
1774     ///
1775     ///
Per room you should check if it's full or not before joining. Photon does list rooms that are
1776     ///
full, unless you close and hide them (room.open = false and room.visible = false).
1777     ///
1778     ///
You can show your games current players and room count without joining a lobby (but you must
1779     ///
be on the master server). Use: countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and
1780     ///
countOfRooms.
1781     ///
1782     ///
When creating new rooms, they will be "attached" to the currently used lobby or the default lobby.
1783     ///
1784     ///
You can use JoinRandomRoom without being in a lobby!
1785     ///
Set autoJoinLobby = false before you connect, to not join a lobby. In that case, the
1786     ///
connect-workflow will call OnConnectedToMaster (if you implement it) when it's done.
1787     ///
</remarks>
1788     ///
<param name="typedLobby">A typed lobby to join (must have name and type).</param>
1789     
public static bool JoinLobby(TypedLobby typedLobby)
1790     {
1791         
if (PhotonNetwork.connected && PhotonNetwork.Server == ServerConnection.MasterServer)
1792         {
1793             
if (typedLobby == null)
1794             {
1795                 typedLobby = TypedLobby.Default;
1796             }
1797
1798             
bool sending = networkingPeer.OpJoinLobby(typedLobby);
1799             
if (sending)
1800             {
1801                 networkingPeer.lobby = typedLobby;
1802
1803             }
1804             
return sending;
1805         }
1806
1807         
return false;
1808     }

1809
1810     ///
<summary>Leave a lobby to stop getting updates about available rooms.</summary>
1811     ///
<remarks>
1812     ///
This does not reset PhotonNetwork.lobby! This allows you to join this particular lobby later
1813     ///
easily.
1814     ///
1815     ///
The values countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and countOfRooms
1816     ///
are received even without being in a lobby.
1817     ///
1818     ///
You can use JoinRandomRoom without being in a lobby.
1819     ///
Use autoJoinLobby to not join a lobby when you connect.
1820     ///
</remarks>
1821     
public static bool LeaveLobby()
1822     {
1823         
if (PhotonNetwork.connected && PhotonNetwork.Server == ServerConnection.MasterServer)
1824         {
1825             
return networkingPeer.OpLeaveLobby();
1826         }
1827
1828         
return false;
1829     }

1830
1831     ///
<summary>Leave the current room and return to the Master Server where you can join or create rooms (see remarks).</summary>
1832     ///
<remarks>
1833     ///
This will clean up all (network) GameObjects with a PhotonView, unless you changed autoCleanUp to false.
1834     ///
Returns to the Master Server.
1835     ///
1836     ///
In OfflineMode, the local "fake" room gets cleaned up and OnLeftRoom gets called immediately.
1837     ///
</remarks>
1838     
public static bool LeaveRoom()
1839     {
1840         
if (offlineMode)
1841         {
1842             offlineModeRoom =
null;
1843             NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnLeftRoom);
1844         }
1845         
else
1846         {
1847             
if (room == null)
1848             {
1849                 Debug.LogWarning(
"PhotonNetwork.room is null. You don't have to call LeaveRoom() when you're not in one. State: " + PhotonNetwork.connectionStateDetailed);
1850             }
1851             
return networkingPeer.OpLeave();
1852         }
1853
1854         
return true;
1855     }

1856
1857     ///
<summary>
1858     ///
Gets currently known rooms as RoomInfo array. This is available and updated while in a lobby (check insideLobby).
1859     ///
</summary>
1860     ///
<remarks>
1861     ///
This list is a cached copy of the internal rooms list so it can be accessed each frame if needed.
1862     ///
Per RoomInfo you can check if the room is full by comparing playerCount and maxPlayers before you allow a join.
1863     ///
1864     ///
The name of a room must be used to join it (via JoinRoom).
1865     ///
1866     ///
Closed rooms are also listed by lobbies but they can't be joined. While in a room, any player can set
1867     ///
Room.visible and Room.open to hide rooms from matchmaking and close them.
1868     ///
</remarks>
1869     ///
<returns>RoomInfo[] of current rooms in lobby.</returns>
1870     
public static RoomInfo[] GetRoomList()
1871     {
1872         
if (offlineMode || networkingPeer == null)
1873         {
1874             
return new RoomInfo[0];
1875         }
1876
1877         
return networkingPeer.mGameListCopy;
1878     }

1879
1880     ///
<summary>
1881     ///
Sets this (local) player's properties and synchronizes them to the other players (don't modify them directly).
1882     ///
</summary>
1883     ///
<remarks>
1884     ///
While in a room, your properties are synced with the other players.
1885     ///
CreateRoom, JoinRoom and JoinRandomRoom will all apply your player's custom properties when you enter the room.
1886     ///
The whole Hashtable will get sent. Minimize the traffic by setting only updated key/values.
1887     ///
1888     ///
If the Hashtable is null, the custom properties will be cleared.
1889     ///
Custom properties are never cleared automatically, so they carry over to the next room, if you don't change them.
1890     ///
1891     ///
Don't set properties by modifying PhotonNetwork.player.customProperties!
1892     ///
</remarks>
1893     ///
<param name="customProperties">Only string-typed keys will be used from this hashtable. If null, custom properties are all deleted.</param>
1894     
public static void SetPlayerCustomProperties(Hashtable customProperties)
1895     {
1896         
if (customProperties == null)
1897         {
1898             customProperties =
new Hashtable();
1899             
foreach (object k in player.customProperties.Keys)
1900             {
1901                 customProperties[(
string)k] = null;
1902             }
1903         }
1904
1905         
if (room != null && room.isLocalClientInside)
1906         {
1907             player.SetCustomProperties(customProperties);
1908         }
1909         
else
1910         {
1911             player.InternalCacheProperties(customProperties);
1912         }
1913     }

1914
1915     ///
<summary>
1916     ///
Sends fully customizable events in a room. Events consist of at least an EventCode (0..199) and can have content.
1917     ///
</summary>
1918     ///
<remarks>
1919     ///
To receive the events someone sends, register your handling method in PhotonNetwork.OnEventCall.
1920     ///
1921     ///
Example:
1922     ///
private void OnEventHandler(byte eventCode, object content, PhotonPlayer sender)
1923     ///
{ Debug.Log("OnEventHandler"); }
1924     ///
1925     ///
PhotonNetwork.OnEventCall += this.OnEventHandler;
1926     ///
1927     ///
1928     ///
The eventContent is optional. To be able to send something, it must be a "serializable type", something that
1929     ///
the client can turn into a byte[] basically. Most basic types and arrays of them are supported, including
1930     ///
Unity's Vector2, Vector3, Quaternion. Transforms or classes some project defines are NOT supported!
1931     ///
You can make your own class a "serializable type" by following the example in CustomTypes.cs.
1932     ///
1933     ///
1934     ///
The RaiseEventOptions have some (less intuitive) combination rules:
1935     ///
If you set targetActors (an array of PhotonPlayer.ID values), the receivers parameter gets ignored.
1936     ///
When using event caching, the targetActors, receivers and interestGroup can't be used. Buffered events go to all.
1937     ///
When using cachingOption removeFromRoomCache, the eventCode and content are actually not sent but used as filter.
1938     ///
</remarks>
1939     ///
<param name="eventCode">A byte identifying the type of event. You might want to use a code per action or to signal which content can be expected. Allowed: 0..199.</param>
1940     ///
<param name="eventContent">Some serializable object like string, byte, integer, float (etc) and arrays of those. Hashtables with byte keys are good to send variable content.</param>
1941     ///
<param name="sendReliable">Makes sure this event reaches all players. It gets acknowledged, which requires bandwidth and it can't be skipped (might add lag in case of loss).</param>
1942     ///
<param name="options">Allows more complex usage of events. If null, RaiseEventOptions.Default will be used (which is fine).</param>
1943     ///
<returns>False if event could not be sent</returns>
1944     
public static bool RaiseEvent(byte eventCode, object eventContent, bool sendReliable, RaiseEventOptions options)
1945     {
1946         
if (!inRoom || eventCode >= 200)
1947         {
1948             Debug.LogWarning(
"RaiseEvent() failed. Your event is not being sent! Check if your are in a Room and the eventCode must be less than 200 (0..199).");
1949             
return false;
1950         }
1951
1952         
return networkingPeer.OpRaiseEvent(eventCode, eventContent, sendReliable, options);
1953     }

1954
1955     ///
<summary>
1956     ///
Allocates a viewID that's valid for the current/local player.
1957     ///
</summary>
1958     ///
<returns>A viewID that can be used for a new PhotonView.</returns>
1959     
public static int AllocateViewID()
1960     {
1961         
int manualId = AllocateViewID(player.ID);
1962         manuallyAllocatedViewIds.Add(manualId);
1963         
return manualId;
1964     }

1965
1966
1967     ///
<summary>
1968     ///
Enables the Master Client to allocate a viewID that is valid for scene objects.
1969     ///
</summary>
1970     ///
<returns>A viewID that can be used for a new PhotonView or -1 in case of an error.</returns>
1971     
public static int AllocateSceneViewID()
1972     {
1973         
if (!PhotonNetwork.isMasterClient)
1974         {
1975             Debug.LogError(
"Only the Master Client can AllocateSceneViewID(). Check PhotonNetwork.isMasterClient!");
1976             
return -1;
1977         }
1978
1979         
int manualId = AllocateViewID(0);
1980         manuallyAllocatedViewIds.Add(manualId);
1981         
return manualId;
1982     }

1983
1984     ///
<summary>
1985     ///
Unregister a viewID (of manually instantiated and destroyed networked objects).
1986     ///
</summary>
1987     ///
<param name="viewID">A viewID manually allocated by this player.</param>
1988     
public static void UnAllocateViewID(int viewID)
1989     {
1990         manuallyAllocatedViewIds.Remove(viewID);
1991
1992         
if (networkingPeer.photonViewList.ContainsKey(viewID))
1993         {
1994             Debug.LogWarning(
string.Format("UnAllocateViewID() should be called after the PhotonView was destroyed (GameObject.Destroy()). ViewID: {0} still found in: {1}", viewID, networkingPeer.photonViewList[viewID]));
1995         }
1996     }
1997
1998     
// use 0 for scene-targetPhotonView-ids
1999     
// returns viewID (combined owner and sub id)
2000     
private static int AllocateViewID(int ownerId)
2001     {
2002         
if (ownerId == 0)
2003         {
2004             
// we look up a fresh subId for the owner "room" (mind the "sub" in subId)
2005             
int newSubId = lastUsedViewSubIdStatic;
2006             
int newViewId;
2007             
int ownerIdOffset = ownerId * MAX_VIEW_IDS;
2008             
for (int i = 1; i < MAX_VIEW_IDS; i++)
2009             {
2010                 newSubId = (newSubId +
1) % MAX_VIEW_IDS;
2011                 
if (newSubId == 0)
2012                 {
2013                     
continue; // avoid using subID 0
2014                 }
2015
2016                 newViewId = newSubId + ownerIdOffset;
2017                 
if (!networkingPeer.photonViewList.ContainsKey(newViewId))
2018                 {
2019                     lastUsedViewSubIdStatic = newSubId;
2020                     
return newViewId;
2021                 }
2022             }
2023
2024             
// this is the error case: we didn't find any (!) free subId for this user
2025             
throw new Exception(string.Format("AllocateViewID() failed. Room (user {0}) is out of 'scene' viewIDs. It seems all available are in use.", ownerId));
2026         }
2027         
else
2028         {
2029             
// we look up a fresh SUBid for the owner
2030             
int newSubId = lastUsedViewSubId;
2031             
int newViewId;
2032             
int ownerIdOffset = ownerId * MAX_VIEW_IDS;
2033             
for (int i = 1; i < MAX_VIEW_IDS; i++)
2034             {
2035                 newSubId = (newSubId +
1) % MAX_VIEW_IDS;
2036                 
if (newSubId == 0)
2037                 {
2038                     
continue; // avoid using subID 0
2039                 }
2040
2041                 newViewId = newSubId + ownerIdOffset;
2042                 
if (!networkingPeer.photonViewList.ContainsKey(newViewId) && !manuallyAllocatedViewIds.Contains(newViewId))
2043                 {
2044                     lastUsedViewSubId = newSubId;
2045                     
return newViewId;
2046                 }
2047             }
2048
2049             
throw new Exception(string.Format("AllocateViewID() failed. User {0} is out of subIds, as all viewIDs are used.", ownerId));
2050         }
2051     }
2052
2053     
private static int[] AllocateSceneViewIDs(int countOfNewViews)
2054     {
2055         
int[] viewIDs = new int[countOfNewViews];
2056         
for (int view = 0; view < countOfNewViews; view++)
2057         {
2058             viewIDs[view] = AllocateViewID(
0);
2059         }
2060
2061         
return viewIDs;
2062     }

2063
2064     ///
<summary>
2065     ///
Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder.
2066     ///
</summary>
2067     ///
<remarks>
2068     ///
Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.
2069     ///
</remarks>
2070     ///
<param name="prefabName">Name of the prefab to instantiate.</param>
2071     ///
<param name="position">Position Vector3 to apply on instantiation.</param>
2072     ///
<param name="rotation">Rotation Quaternion to apply on instantiation.</param>
2073     ///
<param name="group">The group for this PhotonView.</param>
2074     ///
<returns>The new instance of a GameObject with initialized PhotonView.</returns>
2075     
public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group)
2076     {
2077         
return Instantiate(prefabName, position, rotation, group, null);
2078     }

2079
2080     ///
<summary>
2081     ///
Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder.
2082     ///
</summary>
2083     ///
<remarks>Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.</remarks>
2084     ///
<param name="prefabName">Name of the prefab to instantiate.</param>
2085     ///
<param name="position">Position Vector3 to apply on instantiation.</param>
2086     ///
<param name="rotation">Rotation Quaternion to apply on instantiation.</param>
2087     ///
<param name="group">The group for this PhotonView.</param>
2088     ///
<param name="data">Optional instantiation data. This will be saved to it's PhotonView.instantiationData.</param>
2089     ///
<returns>The new instance of a GameObject with initialized PhotonView.</returns>
2090     
public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group, object[] data)
2091     {
2092         
if (!connected || (InstantiateInRoomOnly && !inRoom))
2093         {
2094             Debug.LogError(
"Failed to Instantiate prefab: " + prefabName + ". Client should be in a room. Current connectionStateDetailed: " + PhotonNetwork.connectionStateDetailed);
2095             
return null;
2096         }
2097
2098         GameObject prefabGo;
2099         
if (!UsePrefabCache || !PrefabCache.TryGetValue(prefabName, out prefabGo))
2100         {
2101             prefabGo = (GameObject)Resources.Load(prefabName,
typeof(GameObject));
2102             
if (UsePrefabCache)
2103             {
2104                 PrefabCache.Add(prefabName, prefabGo);
2105             }
2106         }
2107
2108         
if (prefabGo == null)
2109         {
2110             Debug.LogError(
"Failed to Instantiate prefab: " + prefabName + ". Verify the Prefab is in a Resources folder (and not in a subfolder)");
2111             
return null;
2112         }
2113
2114         
// a scene object instantiated with network visibility has to contain a PhotonView
2115         
if (prefabGo.GetComponent<PhotonView>() == null)
2116         {
2117             Debug.LogError(
"Failed to Instantiate prefab:" + prefabName + ". Prefab must have a PhotonView component.");
2118             
return null;
2119         }
2120
2121         Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren();
2122         
int[] viewIDs = new int[views.Length];
2123         
for (int i = 0; i < viewIDs.Length; i++)
2124         {
2125             
//Debug.Log("Instantiate prefabName: " + prefabName + " player.ID: " + player.ID);
2126             viewIDs[i] = AllocateViewID(player.ID);
2127         }
2128
2129         
// Send to others, create info
2130         Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation,
group, viewIDs, data, false);
2131
2132         
// Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId
2133         
return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.mLocalActor, prefabGo);
2134     }

2135
2136
2137     ///
<summary>
2138     ///
Instantiate a scene-owned prefab over the network. The PhotonViews will be controllable by the MasterClient. This prefab needs to be located in the root of a "Resources" folder.
2139     ///
</summary>
2140     ///
<remarks>
2141     ///
Only the master client can Instantiate scene objects.
2142     ///
Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.
2143     ///
</remarks>
2144     ///
<param name="prefabName">Name of the prefab to instantiate.</param>
2145     ///
<param name="position">Position Vector3 to apply on instantiation.</param>
2146     ///
<param name="rotation">Rotation Quaternion to apply on instantiation.</param>
2147     ///
<param name="group">The group for this PhotonView.</param>
2148     ///
<param name="data">Optional instantiation data. This will be saved to it's PhotonView.instantiationData.</param>
2149     ///
<returns>The new instance of a GameObject with initialized PhotonView.</returns>
2150     
public static GameObject InstantiateSceneObject(string prefabName, Vector3 position, Quaternion rotation, int group, object[] data)
2151     {
2152         
if (!connected || (InstantiateInRoomOnly && !inRoom))
2153         {
2154             Debug.LogError(
"Failed to InstantiateSceneObject prefab: " + prefabName + ". Client should be in a room. Current connectionStateDetailed: " + PhotonNetwork.connectionStateDetailed);
2155             
return null;
2156         }
2157
2158         
if (!isMasterClient)
2159         {
2160             Debug.LogError(
"Failed to InstantiateSceneObject prefab: " + prefabName + ". Client is not the MasterClient in this room.");
2161             
return null;
2162         }
2163
2164         GameObject prefabGo;
2165         
if (!UsePrefabCache || !PrefabCache.TryGetValue(prefabName, out prefabGo))
2166         {
2167             prefabGo = (GameObject)Resources.Load(prefabName,
typeof(GameObject));
2168             
if (UsePrefabCache)
2169             {
2170                 PrefabCache.Add(prefabName, prefabGo);
2171             }
2172         }
2173
2174         
if (prefabGo == null)
2175         {
2176             Debug.LogError(
"Failed to InstantiateSceneObject prefab: " + prefabName + ". Verify the Prefab is in a Resources folder (and not in a subfolder)");
2177             
return null;
2178         }
2179
2180         
// a scene object instantiated with network visibility has to contain a PhotonView
2181         
if (prefabGo.GetComponent<PhotonView>() == null)
2182         {
2183             Debug.LogError(
"Failed to InstantiateSceneObject prefab:" + prefabName + ". Prefab must have a PhotonView component.");
2184             
return null;
2185         }
2186
2187         Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren();
2188         
int[] viewIDs = AllocateSceneViewIDs(views.Length);
2189
2190         
if (viewIDs == null)
2191         {
2192             Debug.LogError(
"Failed to InstantiateSceneObject prefab: " + prefabName + ". No ViewIDs are free to use. Max is: " + MAX_VIEW_IDS);
2193             
return null;
2194         }
2195
2196         
// Send to others, create info
2197         Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation,
group, viewIDs, data, true);
2198
2199         
// Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId
2200         
return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.mLocalActor, prefabGo);
2201     }

2202
2203     ///
<summary>
2204     ///
The current roundtrip time to the photon server.
2205     ///
</summary>
2206     ///
<returns>Roundtrip time (to server and back).</returns>
2207     
public static int GetPing()
2208     {
2209         
return networkingPeer.RoundTripTime;
2210     }

2211
2212     ///
<summary>Refreshes the server timestamp (async operation, takes a roundtrip).</summary>
2213     ///
<remarks>Can be useful if a bad connection made the timestamp unusable or imprecise.</remarks>
2214     
public static void FetchServerTimestamp()
2215     {
2216         
if (networkingPeer != null)
2217         {
2218             networkingPeer.FetchServerTimestamp();
2219         }
2220     }

2221
2222     ///
<summary>
2223     ///
Can be used to immediately send the RPCs and Instantiates just called, so they are on their way to the other players.
2224     ///
</summary>
2225     ///
<remarks>
2226     ///
This could be useful if you do a RPC to load a level and then load it yourself.
2227     ///
While loading, no RPCs are sent to others, so this would delay the "load" RPC.
2228     ///
You can send the RPC to "others", use this method, disable the message queue
2229     ///
(by isMessageQueueRunning) and then load.
2230     ///
</remarks>
2231     
public static void SendOutgoingCommands()
2232     {
2233         
if (!VerifyCanUseNetwork())
2234         {
2235             
return;
2236         }
2237
2238         
while (networkingPeer.SendOutgoingCommands())
2239         {
2240         }
2241     }

2242
2243     ///
<summary>Request a client to disconnect (KICK). Only the master client can do this</summary>
2244     ///
<remarks>Only the target player gets this event. That player will disconnect automatically, which is what the others will notice, too.</remarks>
2245     ///
<param name="kickPlayer">The PhotonPlayer to kick.</param>
2246     
public static bool CloseConnection(PhotonPlayer kickPlayer)
2247     {
2248         
if (!VerifyCanUseNetwork())
2249         {
2250             
return false;
2251         }
2252
2253         
if (!player.isMasterClient)
2254         {
2255             Debug.LogError(
"CloseConnection: Only the masterclient can kick another player.");
2256             
return false;
2257         }
2258
2259         
if (kickPlayer == null)
2260         {
2261             Debug.LogError(
"CloseConnection: No such player connected!");
2262             
return false;
2263         }
2264
2265         RaiseEventOptions options =
new RaiseEventOptions() { TargetActors = new int[] { kickPlayer.ID } };
2266         
return networkingPeer.OpRaiseEvent(PunEvent.CloseConnection, null, true, options);
2267     }

2268
2269     ///
<summary>
2270     ///
Network-Destroy the GameObject associated with the PhotonView, unless the PhotonView is static or not under this client's control.
2271     ///
</summary>
2272     ///
<remarks>
2273     ///
Destroying a networked GameObject while in a Room includes:
2274     ///
- Removal of the Instantiate call from the server's room buffer.
2275     ///
- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.
2276     ///
- Sending a message to other clients to remove the GameObject also (affected by network lag).
2277     ///
2278     ///
Usually, when you leave a room, the GOs get destroyed automatically.
2279     ///
If you have to destroy a GO while not in a room, the Destroy is only done locally.
2280     ///
2281     ///
Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().
2282     ///
Objects loaded with a scene are ignored, no matter if they have PhotonView components.
2283     ///
2284     ///
The GameObject must be under this client's control:
2285     ///
- Instantiated and owned by this client.
2286     ///
- Instantiated objects of players who left the room are controlled by the Master Client.
2287     ///
- Scene-owned game objects are controlled by the Master Client.
2288     ///
- GameObject can be destroyed while client is not in a room.
2289     ///
</remarks>
2290     ///
<returns>Nothing. Check error debug log for any issues.</returns>
2291     
public static void Destroy(PhotonView targetView)
2292     {
2293         
if (targetView != null)
2294         {
2295             networkingPeer.RemoveInstantiatedGO(targetView.gameObject, !inRoom);
2296         }
2297         
else
2298         {
2299             Debug.LogError(
"Destroy(targetPhotonView) failed, cause targetPhotonView is null.");
2300         }
2301     }

2302
2303     ///
<summary>
2304     ///
Network-Destroy the GameObject, unless it is static or not under this client's control.
2305     ///
</summary>
2306     ///
<remarks>
2307     ///
Destroying a networked GameObject includes:
2308     ///
- Removal of the Instantiate call from the server's room buffer.
2309     ///
- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.
2310     ///
- Sending a message to other clients to remove the GameObject also (affected by network lag).
2311     ///
2312     ///
Usually, when you leave a room, the GOs get destroyed automatically.
2313     ///
If you have to destroy a GO while not in a room, the Destroy is only done locally.
2314     ///
2315     ///
Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().
2316     ///
Objects loaded with a scene are ignored, no matter if they have PhotonView components.
2317     ///
2318     ///
The GameObject must be under this client's control:
2319     ///
- Instantiated and owned by this client.
2320     ///
- Instantiated objects of players who left the room are controlled by the Master Client.
2321     ///
- Scene-owned game objects are controlled by the Master Client.
2322     ///
- GameObject can be destroyed while client is not in a room.
2323     ///
</remarks>
2324     ///
<returns>Nothing. Check error debug log for any issues.</returns>
2325     
public static void Destroy(GameObject targetGo)
2326     {
2327         networkingPeer.RemoveInstantiatedGO(targetGo, !inRoom);
2328     }

2329
2330     ///
<summary>
2331     ///
Network-Destroy all GameObjects, PhotonViews and their RPCs of targetPlayer. Can only be called on local player (for "self") or Master Client (for anyone).
2332     ///
</summary>
2333     ///
<remarks>
2334     ///
Destroying a networked GameObject includes:
2335     ///
- Removal of the Instantiate call from the server's room buffer.
2336     ///
- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.
2337     ///
- Sending a message to other clients to remove the GameObject also (affected by network lag).
2338     ///
2339     ///
Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().
2340     ///
Objects loaded with a scene are ignored, no matter if they have PhotonView components.
2341     ///
</remarks>
2342     ///
<returns>Nothing. Check error debug log for any issues.</returns>
2343     
public static void DestroyPlayerObjects(PhotonPlayer targetPlayer)
2344     {
2345         
if (player == null)
2346         {
2347             Debug.LogError(
"DestroyPlayerObjects() failed, cause parameter 'targetPlayer' was null.");
2348         }
2349
2350         DestroyPlayerObjects(targetPlayer.ID);
2351     }

2352
2353     ///
<summary>
2354     ///
Network-Destroy all GameObjects, PhotonViews and their RPCs of this player (by ID). Can only be called on local player (for "self") or Master Client (for anyone).
2355     ///
</summary>
2356     ///
<remarks>
2357     ///
Destroying a networked GameObject includes:
2358     ///
- Removal of the Instantiate call from the server's room buffer.
2359     ///
- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.
2360     ///
- Sending a message to other clients to remove the GameObject also (affected by network lag).
2361     ///
2362     ///
Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().
2363     ///
Objects loaded with a scene are ignored, no matter if they have PhotonView components.
2364     ///
</remarks>
2365     ///
<returns>Nothing. Check error debug log for any issues.</returns>
2366     
public static void DestroyPlayerObjects(int targetPlayerId)
2367     {
2368         
if (!VerifyCanUseNetwork())
2369         {
2370             
return;
2371         }
2372         
if (player.isMasterClient || targetPlayerId == player.ID)
2373         {
2374             networkingPeer.DestroyPlayerObjects(targetPlayerId,
false);
2375         }
2376         
else
2377         {
2378             Debug.LogError(
"DestroyPlayerObjects() failed, cause players can only destroy their own GameObjects. A Master Client can destroy anyone's. This is master: " + PhotonNetwork.isMasterClient);
2379         }
2380     }

2381
2382     ///
<summary>
2383     ///
Network-Destroy all GameObjects, PhotonViews and their RPCs in the room. Removes anything buffered from the server. Can only be called by Master Client (for anyone).
2384     ///
</summary>
2385     ///
<remarks>
2386     ///
Can only be called by Master Client (for anyone).
2387     ///
Unlike the Destroy methods, this will remove anything from the server's room buffer. If your game
2388     ///
buffers anything beyond Instantiate and RPC calls, that will be cleaned as well from server.
2389     ///
2390     ///
Destroying all includes:
2391     ///
- Remove anything from the server's room buffer (Instantiate, RPCs, anything buffered).
2392     ///
- Sending a message to other clients to destroy everything locally, too (affected by network lag).
2393     ///
2394     ///
Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().
2395     ///
Objects loaded with a scene are ignored, no matter if they have PhotonView components.
2396     ///
</remarks>
2397     ///
<returns>Nothing. Check error debug log for any issues.</returns>
2398     
public static void DestroyAll()
2399     {
2400         
if (isMasterClient)
2401         {
2402             networkingPeer.DestroyAll(
false);
2403         }
2404         
else
2405         {
2406             Debug.LogError(
"Couldn't call DestroyAll() as only the master client is allowed to call this.");
2407         }
2408     }

2409
2410     ///
<summary>
2411     ///
Remove all buffered RPCs from server that were sent by targetPlayer. Can only be called on local player (for "self") or Master Client (for anyone).
2412     ///
</summary>
2413     ///
<remarks>
2414     ///
This method requires either:
2415     ///
- This is the targetPlayer's client.
2416     ///
- This client is the Master Client (can remove any PhotonPlayer's RPCs).
2417     ///
2418     ///
If the targetPlayer calls RPCs at the same time that this is called,
2419     ///
network lag will determine if those get buffered or cleared like the rest.
2420     ///
</remarks>
2421     ///
<param name="targetPlayer">This player's buffered RPCs get removed from server buffer.</param>
2422     
public static void RemoveRPCs(PhotonPlayer targetPlayer)
2423     {
2424         
if (!VerifyCanUseNetwork())
2425         {
2426             
return;
2427         }
2428
2429         
if (!targetPlayer.isLocal && !isMasterClient)
2430         {
2431             Debug.LogError(
"Error; Only the MasterClient can call RemoveRPCs for other players.");
2432             
return;
2433         }
2434
2435         networkingPeer.OpCleanRpcBuffer(targetPlayer.ID);
2436     }

2437
2438     ///
<summary>
2439     ///
Remove all buffered RPCs from server that were sent via targetPhotonView. The Master Client and the owner of the targetPhotonView may call this.
2440     ///
</summary>
2441     ///
<remarks>
2442     ///
This method requires either:
2443     ///
- The targetPhotonView is owned by this client (Instantiated by it).
2444     ///
- This client is the Master Client (can remove any PhotonView's RPCs).
2445     ///
</remarks>
2446     ///
<param name="targetPhotonView">RPCs buffered for this PhotonView get removed from server buffer.</param>
2447     
public static void RemoveRPCs(PhotonView targetPhotonView)
2448     {
2449         
if (!VerifyCanUseNetwork())
2450         {
2451             
return;
2452         }
2453
2454         networkingPeer.CleanRpcBufferIfMine(targetPhotonView);
2455     }

2456
2457     ///
<summary>
2458     ///
Remove all buffered RPCs from server that were sent in the targetGroup, if this is the Master Client or if this controls the individual PhotonView.
2459     ///
</summary>
2460     ///
<remarks>
2461     ///
This method requires either:
2462     ///
- This client is the Master Client (can remove any RPCs per group).
2463     ///
- Any other client: each PhotonView is checked if it is under this client's control. Only those RPCs are removed.
2464     ///
</remarks>
2465     ///
<param name="targetGroup">Interest group that gets all RPCs removed.</param>
2466     
public static void RemoveRPCsInGroup(int targetGroup)
2467     {
2468         
if (!VerifyCanUseNetwork())
2469         {
2470             
return;
2471         }
2472
2473         networkingPeer.RemoveRPCsInGroup(targetGroup);
2474     }

2475
2476     ///
<summary>
2477     ///
Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!
2478     ///
</summary>
2479     
internal static void RPC(PhotonView view, string methodName, PhotonTargets target, bool encrypt, params object[] parameters)
2480     {
2481         
if (!VerifyCanUseNetwork())
2482         {
2483             
return;
2484         }
2485
2486         
if (room == null)
2487         {
2488             Debug.LogWarning(
"Cannot send RPCs in Lobby! RPC dropped.");
2489             
return;
2490         }
2491
2492         
if (networkingPeer != null)
2493         {
2494             networkingPeer.RPC(view, methodName, target, encrypt, parameters);
2495         }
2496         
else
2497         {
2498             Debug.LogWarning(
"Could not execute RPC " + methodName + ". Possible scene loading in progress?");
2499         }
2500     }

2501
2502     ///
<summary>
2503     ///
Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!
2504     ///
</summary>
2505     
internal static void RPC(PhotonView view, string methodName, PhotonPlayer targetPlayer, bool encrpyt, params object[] parameters)
2506     {
2507         
if (!VerifyCanUseNetwork())
2508         {
2509             
return;
2510         }
2511
2512         
if (room == null)
2513         {
2514             Debug.LogWarning(
"Cannot send RPCs in Lobby, only processed locally");
2515             
return;
2516         }
2517
2518         
if (player == null)
2519         {
2520             Debug.LogError(
"Error; Sending RPC to player null! Aborted \"" + methodName + "\"");
2521         }
2522
2523         
if (networkingPeer != null)
2524         {
2525             networkingPeer.RPC(view, methodName, targetPlayer, encrpyt, parameters);
2526         }
2527         
else
2528         {
2529             Debug.LogWarning(
"Could not execute RPC " + methodName + ". Possible scene loading in progress?");
2530         }
2531     }

2532
2533     ///
<summary>
2534     ///
Enable/disable receiving on given group (applied to PhotonViews)
2535     ///
</summary>
2536     ///
<param name="group">The interest group to affect.</param>
2537     ///
<param name="enabled">Sets if receiving from group to enabled (or not).</param>
2538     
public static void SetReceivingEnabled(int group, bool enabled)
2539     {
2540         
if (!VerifyCanUseNetwork())
2541         {
2542             
return;
2543         }
2544         networkingPeer.SetReceivingEnabled(
group, enabled);
2545     }

2546
2547
2548     ///
<summary>
2549     ///
Enable/disable receiving on given groups (applied to PhotonViews)
2550     ///
</summary>
2551     ///
<param name="enableGroups">The interest groups to enable (or null).</param>
2552     ///
<param name="disableGroups">The interest groups to disable (or null).</param>
2553     
public static void SetReceivingEnabled(int[] enableGroups, int[] disableGroups)
2554     {
2555         
if (!VerifyCanUseNetwork())
2556         {
2557             
return;
2558         }
2559         networkingPeer.SetReceivingEnabled(enableGroups, disableGroups);
2560     }

2561
2562
2563     ///
<summary>
2564     ///
Enable/disable sending on given group (applied to PhotonViews)
2565     ///
</summary>
2566     ///
<param name="group">The interest group to affect.</param>
2567     ///
<param name="enabled">Sets if sending to group is enabled (or not).</param>
2568     
public static void SetSendingEnabled(int group, bool enabled)
2569     {
2570         
if (!VerifyCanUseNetwork())
2571         {
2572             
return;
2573         }
2574
2575         networkingPeer.SetSendingEnabled(
group, enabled);
2576     }

2577
2578
2579     ///
<summary>
2580     ///
Enable/disable sending on given groups (applied to PhotonViews)
2581     ///
</summary>
2582     ///
<param name="enableGroups">The interest groups to enable sending on (or null).</param>
2583     ///
<param name="disableGroups">The interest groups to disable sending on (or null).</param>
2584     
public static void SetSendingEnabled(int[] enableGroups, int[] disableGroups)
2585     {
2586         
if (!VerifyCanUseNetwork())
2587         {
2588             
return;
2589         }
2590         networkingPeer.SetSendingEnabled(enableGroups, disableGroups);
2591     }

2592
2593
2594
2595     ///
<summary>
2596     ///
Sets level prefix for PhotonViews instantiated later on. Don't set it if you need only one!
2597     ///
</summary>
2598     ///
<remarks>
2599     ///
Important: If you don't use multiple level prefixes, simply don't set this value. The
2600     ///
default value is optimized out of the traffic.
2601     ///
2602     ///
This won't affect existing PhotonViews (they can't be changed yet for existing PhotonViews).
2603     ///
2604     ///
Messages sent with a different level prefix will be received but not executed. This affects
2605     ///
RPCs, Instantiates and synchronization.
2606     ///
2607     ///
Be aware that PUN never resets this value, you'll have to do so yourself.
2608     ///
</remarks>
2609     ///
<param name="prefix">Max value is short.MaxValue = 32767</param>
2610     
public static void SetLevelPrefix(short prefix)
2611     {
2612         
if (!VerifyCanUseNetwork())
2613         {
2614             
return;
2615         }
2616
2617         networkingPeer.SetLevelPrefix(prefix);
2618     }

2619
2620     ///
<summary>
2621     ///
Helper function which is called inside this class to erify if certain functions can be used (e.g. RPC when not connected)
2622     ///
</summary>
2623     ///
<returns></returns>
2624     
private static bool VerifyCanUseNetwork()
2625     {
2626         
if (connected)
2627         {
2628             
return true;
2629         }
2630
2631         Debug.LogError(
"Cannot send messages when not connected. Either connect to Photon OR use offline mode!");
2632         
return false;
2633     }

2634
2635     ///
<summary>Wraps loading a level to pause the network mesage-queue. Optionally syncs the loaded level in a room.</summary>
2636     ///
<remarks>
2637     ///
While loading levels, it makes sense to not dispatch messages received by other players.
2638     ///
This method takes care of that by setting PhotonNetwork.isMessageQueueRunning = false and enabling
2639     ///
the queue when the level was loaded.
2640     ///
2641     ///
To sync the loaded level in a room, set PhotonNetwork.automaticallySyncScene to true.
2642     ///
The Master Client of a room will then sync the loaded level with every other player in the room.
2643     ///
2644     ///
You should make sure you don't fire RPCs before you load another scene (which doesn't contain
2645     ///
the same GameObjects and PhotonViews). You can call this in OnJoinedRoom.
2646     ///
2647     ///
This uses Application.LoadLevel.
2648     ///
</remarks>
2649     ///
<param name='levelNumber'>
2650     ///
Number of the level to load. When using level numbers, make sure they are identical on all clients.
2651     ///
</param>
2652     
public static void LoadLevel(int levelNumber)
2653     {
2654         networkingPeer.SetLevelInPropsIfSynced(levelNumber);
2655
2656         PhotonNetwork.isMessageQueueRunning =
false;
2657         networkingPeer.loadingLevelAndPausedNetwork =
true;
2658         Application.LoadLevel(levelNumber);
2659     }

2660
2661     ///
<summary>Wraps loading a level to pause the network mesage-queue. Optionally syncs the loaded level in a room.</summary>
2662     ///
<remarks>
2663     ///
While loading levels, it makes sense to not dispatch messages received by other players.
2664     ///
This method takes care of that by setting PhotonNetwork.isMessageQueueRunning = false and enabling
2665     ///
the queue when the level was loaded.
2666     ///
2667     ///
To sync the loaded level in a room, set PhotonNetwork.automaticallySyncScene to true.
2668     ///
The Master Client of a room will then sync the loaded level with every other player in the room.
2669     ///
2670     ///
You should make sure you don't fire RPCs before you load another scene (which doesn't contain
2671     ///
the same GameObjects and PhotonViews). You can call this in OnJoinedRoom.
2672     ///
2673     ///
This uses Application.LoadLevel.
2674     ///
</remarks>
2675     ///
<param name='levelName'>
2676     ///
Name of the level to load. Make sure it's available to all clients in the same room.
2677     ///
</param>
2678     
public static void LoadLevel(string levelName)
2679     {
2680         networkingPeer.SetLevelInPropsIfSynced(levelName);
2681
2682         PhotonNetwork.isMessageQueueRunning =
false;
2683         networkingPeer.loadingLevelAndPausedNetwork =
true;
2684         Application.LoadLevel(levelName);
2685     }

2686
2687
2688     ///
<summary>
2689     ///
This operation makes Photon call your custom web-service by name (path) with the given parameters.
2690     ///
</summary>
2691     ///
<remarks>
2692     ///
This is a server-side feature which must be setup in the Photon Cloud Dashboard prior to use.
2693     ///
See the Turnbased Feature Overview for a short intro.
2694     ///
http://doc.exitgames.com/en/turnbased/current/getting-started/feature-overview
2695     ///
2696     ///
The Parameters will be converted into JSon format, so make sure your parameters are compatible.
2697     ///
2698     ///
See PhotonNetworkingMessage.OnWebRpcResponse on how to get a response.
2699     ///
2700     ///
It's important to understand that the OperationResponse only tells if the WebRPC could be called.
2701     ///
The content of the response contains any values your web-service sent and the error/success code.
2702     ///
In case the web-service failed in some way, an error code and a debug message are usually inside
2703     ///
the OperationResponse.
2704     ///
2705     ///
The class WebRpcResponse is a helper-class that extracts the most valuable content from the WebRPC
2706     ///
response.
2707     ///
</remarks>
2708     ///
<example>
2709     ///
Example callback implementation:
2710     ///
2711     ///
public void OnWebRpcResponse(OperationResponse response)
2712     ///
{
2713     ///
WebRpcResponse webResponse = new WebRpcResponse(operationResponse);
2714     ///
if (webResponse.ReturnCode != 0) { //...
2715     ///
}
2716     ///
2717     ///
switch (webResponse.Name) { //...
2718     ///
}
2719     ///
// and so on
2720     ///
}
2721     ///
</example>
2722     
public static bool WebRpc(string name, object parameters)
2723     {
2724         
return networkingPeer.WebRpc(name, parameters);
2725     }
2726 }


--------------------------------------------------------------------------------------------------------------------

Part of: Photon Unity Networking

--------------------------------------------------------------------------------------------------------------------

The main class to use the PhotonNetwork plugin.

This class is static.

\ingroup publicApi

Version number of PUN. Also used in GameVersion to separate client version from each other.

This Monobehaviour allows Photon to run an Update loop.

Photon peer class that implements LoadBalancing in PUN.

Primary use is internal (by PUN itself).

The maximum amount of assigned PhotonViews PER player (or scene). See the documentation on how to raise this limitation

public static readonly int MAX_VIEW_IDS = 1000; VIEW & PLAYER LIMIT CAN BE EASILY CHANGED, SEE DOCS

Name of the PhotonServerSettings file (used to load and by PhotonEditor to save new files).

Path to the PhotonServerSettings file (used by PhotonEditor).

Serialized server settings, written by the Setup Wizard for use in ConnectUsingSettings.

Currently used server address (no matter if master or game server).

The minimum difference that a Vector2 or Vector3(e.g. a transforms rotation) needs to change before we send it via a PhotonView's OnSerializeObservingComponent

Note that this is the sqrMagnitude. E.g. to send only after a 0.01 change on the Y-axix, we use 0.01f*0.01f=0.0001f. As a remedy against float inaccuracy we use 0.000099f instead of 0.0001f.

The minimum angle that a rotation needs to change before we send it via a PhotonView's OnSerializeObservingComponent

The minimum difference between floats before we send it via a PhotonView's OnSerializeObservingComponent

False until you connected to Photon initially. True in offline mode, while connected to any server and even while switching servers but

True when you called ConnectUsingSettings (or similar) until the low level connection to Photon gets established.

A refined version of connected which is true only if your connection to the server is ready to accept operations like join, leave, etc.

connected property will check offlineMode and networkingPeer being null

return false; we are not ready to execute any operations

Simplified connection state

Detailed connection state (ignorant of PUN, so it can be "disconnected" while switching servers).

In OfflineMode, this is PeerState.Joined (after createjoin) or it is ConnectedToMaster in all other cases.

A user's authentication values used during connect for Custom Authentication with Photon (and a custom servicecommunity).

Set these before calling Connect if you want custom authentication.

If authentication fails for any values, PUN will call your implementation of OnCustomAuthenticationFailed(string debugMsg).

See: PhotonNetworkingMessage.OnCustomAuthenticationFailed

Get the room we're currently in. Null if we aren't in any room.

If true, Instantiate methods will check if you are in a room and fail if you are not.

Instantiating anything outside of a specific room is very likely to break things.

Turn this off only if you know what you do.

Network log level. Controls how verbose PUN is.

The local PhotonPlayer. Always available and represents this player.

CustomProperties can be set before entering a room and will be synced as well.

return null; Surpress ExitApplication errors

The PhotonPlayer of the master client. The master client is the 'virtual owner' of the room. You can use it if you need authorative decision made by one of the players.

The masterClient is null until a room is joined and becomes null again when the room is left.

Allows the current Master Client to assign someone else as MC - custom selection should pick the same user on any client.

The ReceiverGroup.MasterClient (usable in RPCs) is not affected by this (still points to lowest player.ID in room).

Avoid using this enum value (and send to a specific player instead).

If the current Master Client leaves, PUN will detect a new one by "lowest player ID". Implement OnMasterClientSwitched

to get a callback in this case. The PUN-selected Master Client might assign a new one.

Make sure you don't create an endless loop of Master-assigning! When selecting a custom Master Client, all clients

should point to the same player, no matter who actually assigns this player.

Locally the Master Client is immediately switched, while remote clients get an event. This means the game

is tempoarily without Master Client like when a current Master Client leaves.

When switching the Master Client manually, keep in mind that this user might leave and not do it's work, just like

any Master Client.

The player of the next Master Client.

False when this synced action couldn't be done. Must be online and Master Client.

This local player's name.

Setting the name will automatically send it, if connected. Setting null, won't change the name.

The full PhotonPlayer list, including the local player.

The other PhotonPlayers, not including our local player.

Read-only list of friends, their online status and the room they are in. Null until initialized by a FindFriends call.

Do not modify this list!

It is internally handled by FindFriends and only available to read the values.

The value of FriendsListAge tells you how old the data is in milliseconds.

Don't get this list more often than useful (> 10 seconds). In best case, keep the list you fetch really short.

You could (e.g.) get the full list only once, then request a few updates only for friends who are online.

After a while (e.g. 1 minute), you can get the full list again (to update online states).

Age of friend list info (in milliseconds). It's 0 until a friend list is fetched.

While enabled (true), Instantiate uses PhotonNetwork.PrefabCache to keep game objects in memory (improving instantiation of the same prefab).

Setting UsePrefabCache to false during runtime will not clear PrefabCache but will ignore it right away.

You could clean and modify the cache yourself. Read its comments.

Keeps references to GameObjects for frequent instantiation (out of memory instead of loading the Resources).

You should be able to modify the cache anytime you like, except while Instantiate is used. Best do it only in the main-Thread.

Offline mode can be set to re-use your multiplayer code in singleplayer game modes.

When this is on PhotonNetwork will not create any connections and there is near to

no overhead. Mostly usefull for reusing RPC's and PhotonNetwork.Instantiate

networkingPeer.Disconnect(); Cleanup (also calls OnLeftRoom to reset stuff)

If not null, this is the (exclusive) list of GameObjects that get called by PUN SendMonoMessage().

For all callbacks defined in PhotonNetworkingMessage, PUN will use SendMonoMessage and

call FindObjectsOfType() to find all scripts and GameObjects that might want a callback by PUN.

PUN callbacks are not very frequent (in-game, property updates are most frequent) but

FindObjectsOfType is time consuming and with a large number of GameObjects, performance might

suffer.

Optionally, SendMonoMessageTargets can be used to supply a list of target GameObjects. This

skips the FindObjectsOfType() but any GameObject that needs callbacks will have to Add itself

to this list.

If null, the default behaviour is to do a SendMessage on each GameObject with a MonoBehaviour.

Populates SendMonoMessageTargets with currently existing GameObjects that have a Component of type.

If null, this will use SendMonoMessageTargets as component-type (MonoBehaviour by default).

The maximum number of players for a room. Better: Set it in CreateRoom.

If no room is opened, this will return 0.

Defines if PUN automatically synchronizes the loaded level per room. Default: false disabled.

If the MasterClient loads a level, all clients will load the new scene too.

This also takes care of smooth loading of the game scene after joining a game.

In best case, use PhotonNetwork.LoadLevel on the Master Client to change levels.

true if automatically sync scene; otherwise, false.

This setting defines if players in a room should destroy a leaving player's instantiated GameObjects and PhotonViews.

When "this client" creates a roomgame, autoCleanUpPlayerObjects is copied to that room's properties and used by all

PUN clients in that room (no matter what their autoCleanUpPlayerObjects value is).

If room.AutoCleanUp is enabled in a room, the PUN clients will destroy a player's objects on leave.

When enabled, the server will clean RPCs, instantiated GameObjects and PhotonViews of the leaving player and joining

players won't get those at anymore.

Once a room is created, this setting can't be changed anymore.

Enabled by default.

Defines if the PhotonNetwork should join the "lobby" when connected to the Master server.

If this is false, OnConnectedToMaster() will be called when connection to the Master is available.

OnJoinedLobby() will NOT be called if this is false.

Enabled by default.

The room listing will not become available.

Rooms can be created and joined (randomly) without joining the lobby (and getting sent the room list).

Backing field.

True while this client is in a lobby.

You are automatically leaving any lobby when you join a room!

Lobbies only exist on the Master Server (whereas rooms are handled by Game Servers).

The lobby that will be used when PUN joins a lobby or creates a game.

The default lobby uses an empty string as name.

PUN will enter a lobby on the Master Server if autoJoinLobby is set to true.

So when you connect or leave a room, PUN automatically gets you into a lobby again.

Check PhotonNetwork.insideLobby if the client is in a lobby.

(@ref masterServerAndLobby)

Defines how many times per second PhotonNetwork should send a package. If you change

this, do not forget to also change 'sendRateOnSerialize'.

Less packages are less overhead but more delay.

Setting the sendRate to 50 will create up to 50 packages per second (which is a lot!).

Keep your target platform in mind: mobile networks are slower and less reliable.

sendRateOnSerialize needs to be <= sendRate

Defines how many times per second OnPhotonSerialize should be called on PhotonViews.

Choose this value in relation to 'sendRate'. OnPhotonSerialize will creart the commands to be put into packages.

A lower rate takes up less performance but will cause more lag.

private static int sendInterval = 50; in miliseconds.

private static int sendIntervalOnSerialize = 100; in miliseconds. I.e. 100 = 100ms which makes 10 timessecond

Can be used to pause dispatching of incoming evtents (RPCs, Instantiates and anything else incoming).

While IsMessageQueueRunning == false, the OnPhotonSerializeView calls are not done and nothing is sent by

a client. Also, incoming messages will be queued until you re-activate the message queue.

This can be useful if you first want to load a level, then go on receiving data of PhotonViews and RPCs.

The client will go on receiving and sending acknowledgements for incoming packages and your RPCsEvents.

This adds "lag" and can cause issues when the pause is longer, as all incoming messages are just queued.

Backup for property isMessageQueueRunning.

Used once per dispatch to limit unreliable commands per channel (so after a pause, many channels can still cause a lot of unreliable commands)

Photon network time, synched with the server

v1.3:

This time reflects milliseconds since start of the server, cut down to 4 bytes.

It will overflow every 49 days from a high value to 0. We do not (yet) compensate this overflow.

Master- and Game-Server will have different time values.

v1.10:

Fixed issues with precision for high server-time values. This should update with 15ms precision by default.

Are we the master client?

Is true while being in a room (connectionStateDetailed == PeerState.Joined).

Many actions can only be executed in a room, like Instantiate or Leave, etc.

You can join a room in offline mode, too.

in offline mode, you can be in a room too and connectionStateDetailed then returns Joined like on online mode!

True if we are in a room (client) and NOT the room's masterclient

The count of players currently looking for a room (available on MasterServer in 5sec intervals).

Count of users currently playing your app in some room (sent every 5sec by Master Server). Use playerList.Count to get the count of players in the room you're in!

The count of players currently using this application (available on MasterServer in 5sec intervals).

The count of rooms currently in use (available on MasterServer in 5sec intervals).

While inside the lobby you can also check the count of listed rooms as: PhotonNetwork.GetRoomList().Length.

Since PUN v1.25 this is only based on the statistic event Photon sends (counting all rooms).

Enables or disables the collection of statistics about this client's traffic.

If you encounter issues with clients, the traffic stats are a good starting point to find solutions.

Only with enabled stats, you can use GetVitalStats

Count of commands that got repeated (due to local repeat-timing before an ACK was received).

Crc checks can be useful to detect and avoid issues with broken datagrams. Can be enabled while not connected.

If CrcCheckEnabled, this counts the incoming packages that don't have a valid CRC checksum and got rejected.

Defines the number of times a reliable message can be resent before not getting an ACK for it will trigger a disconnect. Default: 5.

Less resends mean quicker disconnects, while more can lead to much more lag without helping. Min: 3. Max: 10.

The server this client is currently connected or connecting to.

Defines the delegate usable in OnEventCall.

Any eventCode < 200 will be forwarded to your delegate(s).

The code assigend to the incoming event.

The content the sender put into the event.

The ID of the player who sent the event. It might be 0, if the "room" sent the event.

Register your RaiseEvent handling methods here by using "+=".

Any eventCode < 200 will be forwarded to your delegate(s).

internal static int lastUsedViewSubId = 0; each player only needs to remember it's own (!) last used subId to speed up assignment

internal static int lastUsedViewSubIdStatic = 0; per room, the master is able to instantiate GOs. the subId for this must be unique too

Resets the traffic stats and re-enables them.

Only available when NetworkStatisticsEnabled was used to gather some stats.

A string with vital networking statistics.

Static constructor used for basic setup.

Debug.Log(string.Format("PhotonNetwork.ctor() Not playing {0} {1}", UnityEditor.EditorApplication.isPlaying, UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode));

This can happen when you recompile a script IN play made

This helps to surpress some errors, but will not fix breaking

Debug.Log("Handler: " + photonHandler + " photonHandler.gameObject: " + photonHandler.gameObject);

Set up a MonoBehaviour to run Photon, and hide it

Set up the NetworkingPeer and use protocol of PhotonServerSettings

Local player

While offline, the network protocol can be switched (which affects the ports you can use to connect).

When you switch the protocol, make sure to also switch the port for the master server. Default ports are:

TCP: 4530

UDP: 5055

This could look like this:

Connect(serverAddress, , appID, gameVersion)

Or when you use ConnectUsingSettings(), the PORT in the settings can be switched like so:

PhotonNetwork.PhotonServerSettings.ServerPort = 4530;

The current protocol can be read this way:

PhotonNetwork.networkingPeer.UsedProtocol

This does not work with the native socket plugin of PUN+ on mobile!

Network protocol to use as low level connection. UDP is default. TCP is not available on all platforms (see remarks).

set up a new NetworkingPeer

Internally used by Editor scripts, called on Hierarchy change (includes scene save) to remove surplus hidden PhotonHandlers.

Debug.Log("Removing Handler: " + photonHandler + " photonHandler.gameObject: " + photonHandler.gameObject);

Connect to Photon as configured in the editor (saved in PhotonServerSettings file).

This method will disable offlineMode (which won't destroy any instantiated GOs) and it

will set isMessageQueueRunning to true.

Your server configuration is created by the PUN Wizard and contains the AppId and

region for Photon Cloud games and the server address if you host Photon yourself.

These settings usually don't change often.

To ignore the config file and connect anywhere call: PhotonNetwork.ConnectToMaster.

To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard).

https:cloud.exitgames.comdashboard

Connecting to the Photon Cloud might fail due to:

- Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value)

- Network issues (calls: OnFailedToConnectToPhoton())

- Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion)

- Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached())

More about the connection limitations:

http:doc.exitgames.comphoton-cloud

This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).

someone can set offlineMode in code and then call ConnectUsingSettings() with non-offline settings. Warning for that case:

offlineMode = false; Cleanup offline mode

Connect to a Photon Master Server by address, port, appID and game(client) version.

To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard).

https:cloud.exitgames.comdashboard

Connecting to the Photon Cloud might fail due to:

- Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value)

- Network issues (calls: OnFailedToConnectToPhoton())

- Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion)

- Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached())

More about the connection limitations:

http:doc.exitgames.comphoton-cloud

The server's address (either your own or Photon Cloud address).

The server's port to connect to.

Your application ID (Photon Cloud provides you with a GUID for your game).

This client's version number. Users are separated by gameversion (which allows you to make breaking changes).

offlineMode = false; Cleanup offline mode

Connect to the Photon Cloud region with the lowest ping (on platforms that support Unity's Ping).

Will save the result of pinging all cloud servers in PlayerPrefs. Calling this the first time can take +-2 seconds.

The ping result can be overridden via PhotonNetwork.OverrideBestCloudServer(..)

This call can take up to 2 seconds if it is the first time you are using this, all cloud servers will be pinged to check for the best region.

The PUN Setup Wizard stores your appID in a settings file and applies a server addressport.

To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard).

https:cloud.exitgames.comdashboard

Connecting to the Photon Cloud might fail due to:

- Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value)

- Network issues (calls: OnFailedToConnectToPhoton())

- Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion)

- Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached())

More about the connection limitations:

http:doc.exitgames.comphoton-cloud

This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).

If this client is going to connect to cloud server based on ping. Even if true, this does not guarantee a connection but the attempt is being made.

Overwrites the region that is used for ConnectToBestCloudServer(string gameVersion).

This will overwrite the result of pinging all cloud servers.

Use this to allow your users to save a manually selected region in the prefs.

Pings all cloud servers again to find the one with best ping (currently).

Makes this client disconnect from the photon server, a process that leaves any room and calls OnDisconnectedFromPhoton on completion.

When you disconnect, the client will send a "disconnecting" message to the server. This speeds up leavedisconnect

messages for players in the same room as you (otherwise the server would timeout this client's connection).

When used in offlineMode, the state-change and event-call OnDisconnectedFromPhoton are immediate.

Offline mode is set to false as well.

Once disconnected, the client can connect again. Use ConnectUsingSettings.

return; Surpress error when quitting playmode in the editor

Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting.

Requests the rooms and online status for a list of friends and saves the result in PhotonNetwork.Friends.

Works only on Master Server to find the rooms played by a selected list of users.

The result will be stored in PhotonNetwork.Friends when available.

That list is initialized on first use of OpFindFriends (before that, it is null).

To refresh the list, call FindFriends again (in 5 seconds or 10 or 20).

Users identify themselves by setting a unique username via PhotonNetwork.playerName

or by PhotonNetwork.AuthValues. The user id set in AuthValues overrides the playerName,

so make sure you know the ID your friends use to authenticate.

The AuthValues are sent in OpAuthenticate when you connect, so the AuthValues must be

set before you connect!

Note: Changing a player's name doesn't make sense when using a friend list.

The list of friends must be fetched from some other source (not provided by Photon).

Internal:

The server response includes 2 arrays of info (each index matching a friend from the request):

ParameterCode.FindFriendsResponseOnlineList = bool[] of online states

ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room)

Array of friend (make sure to use unique playerName or AuthValues).

If the operation could be sent (requires connection, only one request is allowed at any time). Always false in offline mode.

Creates a room with given name but fails if this room is existing already.

If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).

The created room is automatically placed in the currently used lobby or the default-lobby if you didn't explicitly join one.

Call this only on the master server.

Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally

to switch to the assigned game server and roomName

Unique name of the room to create. Pass null or "" to make the server generate a name.

Shows (or hides) this room from the lobby's listing of rooms.

Allows (or disallows) others to join this room.

Max number of players that can join the room.

Creates a room with given name but fails if this room is existing already.

If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).

The created room is automatically placed in the currently used lobby or the default-lobby if you didn't explicitly join one.

Call this only on the master server.

Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally

to switch to the assigned game server and roomName.

PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room.

Unique name of the room to create. Pass null or "" to make the server generate a name.

Shows (or hides) this room from the lobby's listing of rooms.

Allows (or disallows) others to join this room.

Max number of players that can join the room.

Custom properties of the new room (set on create, so they are immediately available).

Array of custom-property-names that should be forwarded to the lobby (include only the useful ones).

Creates a room with given name but fails if this room(name) is existing already. Creates random name for roomName null.

If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).

The created room is automatically placed in the currently used lobby (if any) or the default-lobby if you didn't explicitly join one.

Call this only on the master server.

Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally

to switch to the assigned game server and roomName.

PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room.

Unique name of the room to create.

Creates a room but fails if this room is existing already. Can only be called on Master Server.

When successful, this calls the callbacks OnCreatedRoom and OnJoinedRoom (the latter, cause you join as first player).

If the room can't be created (because it exists already), OnPhotonCreateRoomFailed gets called.

If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).

Rooms can be created in any number of lobbies. Those don't have to exist before you create a room in them (they get

auto-created on demand). Lobbies can be useful to split room lists on the server-side already. That can help keep the room

lists short and manageable.

If you set a typedLobby parameter, the room will be created in that lobby (no matter if you are active in any).

If you don't set a typedLobby, the room is automatically placed in the currently active lobby (if any) or the

default-lobby.

Call this only on the master server.

Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally

to switch to the assigned game server and roomName.

PhotonNetwork.autoCleanUpPlayerObjects will become this room's autoCleanUp property and that's used by all clients that join this room.

Unique name of the room to create. Pass null or "" to make the server generate a name.

Common options for the room like maxPlayers, initial custom room properties and similar. See RoomOptions type..

If null, the room is automatically created in the currently used lobby (which is "default" when you didn't join one explicitly).

Join room by roomName with an option to create it on the fly if not existing.

Join will try to enter a room by roomName. If this room is full or closed, this will fail.

If the room is not existing, JoinRoom will also fail by default.

You can set createIfNotExists to true to make the server create the room if required.

This makes it easier for groups of players to get into the same room. Once the group

exchanged a roomName, any player can try to join or create the room in one step -

it doesn't matter who's first.

OnJoinedRoom() gets called if the room existed and was joined,

OnCreatedRoom() gets called if the room didn't exist and this client created it.

OnPhotonJoinRoomFailed() gets called if the room couldn't be joined or created.

Implement either in any script in the scene to react to joiningcreating a room.

To join a room from the lobby's listing, use RoomInfo.name as roomName here.

In OfflineMode, this always "finds" and joins a room.

Unique name of the room to join (or create if createIfNotExists is true).

If true, the server will attempt to create a room, making the success callback OnCreatedRoom().

return false; offline and OpJoin both return but the error-cases don't

Join room by roomname and on success calls OnJoinedRoom(). This is not affected by lobbies.

On success, the method OnJoinedRoom() is called on any script. You can implement it to react to joining a room.

JoinRoom fails if the room is either full or no longer available (it might become empty while you attempt to join).

Implement OnPhotonJoinRoomFailed() to get a callback in error case.

To join a room from the lobby's listing, use RoomInfo.name as roomName here.

Despite using multiple lobbies, a roomName is always "global" for your application and so you don't

have to specify which lobby it's in. The Master Server will find the room.

In the Photon Cloud, an application is defined by AppId, Game- and PUN-version.

Unique name of the room to join.

Lets you either join a named room or create it on the fly - you don't have to know if someone created the room already.

This makes it easier for groups of players to get into the same room. Once the group

exchanged a roomName, any player can call JoinOrCreateRoom and it doesn't matter who

actually joins or creates the room.

The parameters roomOptions and typedLobby are only used when the room actually gets created by this client.

You know if this client created a room, if you get a callback OnCreatedRoom (before OnJoinedRoom gets called as well).

Name of the room to join. Must be non null.

Options for the room, in case it does not exist yet. Else these values are ignored.

Lobby you want a new room to be listed in. Ignored if the room was existing and got joined.

If the operation got queued and will be sent.

NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom); in offline mode you create, too for JoinOrCreateRoom

Joins any available room of the currently used lobby and fails if none is available.

Rooms can be created in arbitrary lobbies which get created on demand.

You can join rooms from any lobby without actually joining the lobby.

Use the JoinRandomRoom overload with TypedLobby parameter.

This method will only match rooms attached to one lobby! If you use many lobbies, you

might have to repeat JoinRandomRoom, to find some fitting room.

This method looks up a room in the currently active lobby or (if no lobby is joined)

in the default lobby.

If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).

Alternatively, try again in a moment.

Attempts to join an open room with fitting, custom properties but fails if none is currently available.

Rooms can be created in arbitrary lobbies which get created on demand.

You can join rooms from any lobby without actually joining the lobby.

Use the JoinRandomRoom overload with TypedLobby parameter.

This method will only match rooms attached to one lobby! If you use many lobbies, you

might have to repeat JoinRandomRoom, to find some fitting room.

This method looks up a room in the currently active lobby or (if no lobby is joined)

in the default lobby.

If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).

Alternatively, try again in a moment.

Filters for rooms that match these custom properties (string keys and values). To ignore, pass null.

Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.

Attempts to join an open room with fitting, custom properties but fails if none is currently available.

Rooms can be created in arbitrary lobbies which get created on demand.

You can join rooms from any lobby without actually joining the lobby with this overload.

This method will only match rooms attached to one lobby! If you use many lobbies, you

might have to repeat JoinRandomRoom, to find some fitting room.

This method looks up a room in the specified lobby or the currently active lobby (if none specified)

or in the default lobby (if none active).

If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).

Alternatively, try again in a moment.

In offlineMode, a room will be created but no properties will be set and all parameters of this

JoinRandomRoom call are ignored. The eventcallback OnJoinedRoom gets called (see enum PhotonNetworkingMessage).

Filters for rooms that match these custom properties (string keys and values). To ignore, pass null.

Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.

Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options.

The lobby in which you want to lookup a room. Pass null, to use the default lobby. This does not join that lobby and neither sets the lobby property.

A filter-string for SQL-typed lobbies.

On MasterServer this joins the default lobby which list rooms currently in use.

The room list is sent and refreshed by the server. You can access this cached list by

PhotonNetwork.GetRoomList().

Per room you should check if it's full or not before joining. Photon also lists rooms that are

full, unless you close and hide them (room.open = false and room.visible = false).

In best case, you make your clients join random games, as described here:

http:doc.exitgames.comenrealtimecurrentreferencematchmaking-and-lobby

You can show your current players and room count without joining a lobby (but you must

be on the master server). Use: countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and

countOfRooms.

You can use more than one lobby to keep the room lists shorter. See JoinLobby(TypedLobby lobby).

When creating new rooms, they will be "attached" to the currently used lobby or the default lobby.

You can use JoinRandomRoom without being in a lobby!

Set autoJoinLobby = false before you connect, to not join a lobby. In that case, the

connect-workflow will call OnConnectedToMaster (if you implement it) when it's done.

On a Master Server you can join a lobby to get lists of available rooms.

The room list is sent and refreshed by the server. You can access this cached list by

PhotonNetwork.GetRoomList().

Any client can "make up" any lobby on the fly. Splitting rooms into multiple lobbies will

keep each list shorter. However, having too many lists might ruin the matchmaking experience.

In best case, you create a limited number of lobbies. For example, create a lobby per

game-mode: "koth" for king of the hill and "ffa" for free for all, etc.

There is no listing of lobbies at the moment.

Sql-typed lobbies offer a different filtering model for random matchmaking. This might be more

suited for skillbased-games. However, you will also need to follow the conventions for naming

filterable properties in sql-lobbies! Both is explained in the matchmaking doc linked below.

In best case, you make your clients join random games, as described here:

http:confluence.exitgames.comdisplayPTNOp+JoinRandomGame

Per room you should check if it's full or not before joining. Photon does list rooms that are

full, unless you close and hide them (room.open = false and room.visible = false).

You can show your games current players and room count without joining a lobby (but you must

be on the master server). Use: countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and

countOfRooms.

When creating new rooms, they will be "attached" to the currently used lobby or the default lobby.

You can use JoinRandomRoom without being in a lobby!

Set autoJoinLobby = false before you connect, to not join a lobby. In that case, the

connect-workflow will call OnConnectedToMaster (if you implement it) when it's done.

A typed lobby to join (must have name and type).

Leave a lobby to stop getting updates about available rooms.

This does not reset PhotonNetwork.lobby! This allows you to join this particular lobby later

easily.

The values countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and countOfRooms

are received even without being in a lobby.

You can use JoinRandomRoom without being in a lobby.

Use autoJoinLobby to not join a lobby when you connect.

Leave the current room and return to the Master Server where you can join or create rooms (see remarks).

This will clean up all (network) GameObjects with a PhotonView, unless you changed autoCleanUp to false.

Returns to the Master Server.

In OfflineMode, the local "fake" room gets cleaned up and OnLeftRoom gets called immediately.

Gets currently known rooms as RoomInfo array. This is available and updated while in a lobby (check insideLobby).

This list is a cached copy of the internal rooms list so it can be accessed each frame if needed.

Per RoomInfo you can check if the room is full by comparing playerCount and maxPlayers before you allow a join.

The name of a room must be used to join it (via JoinRoom).

Closed rooms are also listed by lobbies but they can't be joined. While in a room, any player can set

Room.visible and Room.open to hide rooms from matchmaking and close them.

RoomInfo[] of current rooms in lobby.

Sets this (local) player's properties and synchronizes them to the other players (don't modify them directly).

While in a room, your properties are synced with the other players.

CreateRoom, JoinRoom and JoinRandomRoom will all apply your player's custom properties when you enter the room.

The whole Hashtable will get sent. Minimize the traffic by setting only updated keyvalues.

If the Hashtable is null, the custom properties will be cleared.

Custom properties are never cleared automatically, so they carry over to the next room, if you don't change them.

Don't set properties by modifying PhotonNetwork.player.customProperties!

Only string-typed keys will be used from this hashtable. If null, custom properties are all deleted.

Sends fully customizable events in a room. Events consist of at least an EventCode (0..199) and can have content.

To receive the events someone sends, register your handling method in PhotonNetwork.OnEventCall.

Example:

private void OnEventHandler(byte eventCode, object content, PhotonPlayer sender)

{ Debug.Log("OnEventHandler"); }

PhotonNetwork.OnEventCall += this.OnEventHandler;

The eventContent is optional. To be able to send something, it must be a "serializable type", something that

the client can turn into a byte[] basically. Most basic types and arrays of them are supported, including

Unity's Vector2, Vector3, Quaternion. Transforms or classes some project defines are NOT supported!

You can make your own class a "serializable type" by following the example in CustomTypes.cs.

The RaiseEventOptions have some (less intuitive) combination rules:

If you set targetActors (an array of PhotonPlayer.ID values), the receivers parameter gets ignored.

When using event caching, the targetActors, receivers and interestGroup can't be used. Buffered events go to all.

When using cachingOption removeFromRoomCache, the eventCode and content are actually not sent but used as filter.

A byte identifying the type of event. You might want to use a code per action or to signal which content can be expected. Allowed: 0..199.

Some serializable object like string, byte, integer, float (etc) and arrays of those. Hashtables with byte keys are good to send variable content.

Makes sure this event reaches all players. It gets acknowledged, which requires bandwidth and it can't be skipped (might add lag in case of loss).

Allows more complex usage of events. If null, RaiseEventOptions.Default will be used (which is fine).

False if event could not be sent

Allocates a viewID that's valid for the currentlocal player.

A viewID that can be used for a new PhotonView.

Enables the Master Client to allocate a viewID that is valid for scene objects.

A viewID that can be used for a new PhotonView or -1 in case of an error.

Unregister a viewID (of manually instantiated and destroyed networked objects).

A viewID manually allocated by this player.

use 0 for scene-targetPhotonView-ids

returns viewID (combined owner and sub id)

we look up a fresh subId for the owner "room" (mind the "sub" in subId)

continue; avoid using subID 0

this is the error case: we didn't find any (!) free subId for this user

we look up a fresh SUBid for the owner

continue; avoid using subID 0

Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder.

Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.

Name of the prefab to instantiate.

Position Vector3 to apply on instantiation.

Rotation Quaternion to apply on instantiation.

The group for this PhotonView.

The new instance of a GameObject with initialized PhotonView.

Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder.

Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.

Name of the prefab to instantiate.

Position Vector3 to apply on instantiation.

Rotation Quaternion to apply on instantiation.

The group for this PhotonView.

Optional instantiation data. This will be saved to it's PhotonView.instantiationData.

The new instance of a GameObject with initialized PhotonView.

a scene object instantiated with network visibility has to contain a PhotonView

Debug.Log("Instantiate prefabName: " + prefabName + " player.ID: " + player.ID);

Send to others, create info

Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId

Instantiate a scene-owned prefab over the network. The PhotonViews will be controllable by the MasterClient. This prefab needs to be located in the root of a "Resources" folder.

Only the master client can Instantiate scene objects.

Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.

Name of the prefab to instantiate.

Position Vector3 to apply on instantiation.

Rotation Quaternion to apply on instantiation.

The group for this PhotonView.

Optional instantiation data. This will be saved to it's PhotonView.instantiationData.

The new instance of a GameObject with initialized PhotonView.

a scene object instantiated with network visibility has to contain a PhotonView

Send to others, create info

Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId

The current roundtrip time to the photon server.

Roundtrip time (to server and back).

Refreshes the server timestamp (async operation, takes a roundtrip).

Can be useful if a bad connection made the timestamp unusable or imprecise.

Can be used to immediately send the RPCs and Instantiates just called, so they are on their way to the other players.

This could be useful if you do a RPC to load a level and then load it yourself.

While loading, no RPCs are sent to others, so this would delay the "load" RPC.

You can send the RPC to "others", use this method, disable the message queue

(by isMessageQueueRunning) and then load.

Request a client to disconnect (KICK). Only the master client can do this

Only the target player gets this event. That player will disconnect automatically, which is what the others will notice, too.

The PhotonPlayer to kick.

Network-Destroy the GameObject associated with the PhotonView, unless the PhotonView is static or not under this client's control.

Destroying a networked GameObject while in a Room includes:

- Removal of the Instantiate call from the server's room buffer.

- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.

- Sending a message to other clients to remove the GameObject also (affected by network lag).

Usually, when you leave a room, the GOs get destroyed automatically.

If you have to destroy a GO while not in a room, the Destroy is only done locally.

Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().

Objects loaded with a scene are ignored, no matter if they have PhotonView components.

The GameObject must be under this client's control:

- Instantiated and owned by this client.

- Instantiated objects of players who left the room are controlled by the Master Client.

- Scene-owned game objects are controlled by the Master Client.

- GameObject can be destroyed while client is not in a room.

Nothing. Check error debug log for any issues.

Network-Destroy the GameObject, unless it is static or not under this client's control.

Destroying a networked GameObject includes:

- Removal of the Instantiate call from the server's room buffer.

- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.

- Sending a message to other clients to remove the GameObject also (affected by network lag).

Usually, when you leave a room, the GOs get destroyed automatically.

If you have to destroy a GO while not in a room, the Destroy is only done locally.

Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().

Objects loaded with a scene are ignored, no matter if they have PhotonView components.

The GameObject must be under this client's control:

- Instantiated and owned by this client.

- Instantiated objects of players who left the room are controlled by the Master Client.

- Scene-owned game objects are controlled by the Master Client.

- GameObject can be destroyed while client is not in a room.

Nothing. Check error debug log for any issues.

Network-Destroy all GameObjects, PhotonViews and their RPCs of targetPlayer. Can only be called on local player (for "self") or Master Client (for anyone).

Destroying a networked GameObject includes:

- Removal of the Instantiate call from the server's room buffer.

- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.

- Sending a message to other clients to remove the GameObject also (affected by network lag).

Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().

Objects loaded with a scene are ignored, no matter if they have PhotonView components.

Nothing. Check error debug log for any issues.

Network-Destroy all GameObjects, PhotonViews and their RPCs of this player (by ID). Can only be called on local player (for "self") or Master Client (for anyone).

Destroying a networked GameObject includes:

- Removal of the Instantiate call from the server's room buffer.

- Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call.

- Sending a message to other clients to remove the GameObject also (affected by network lag).

Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().

Objects loaded with a scene are ignored, no matter if they have PhotonView components.

Nothing. Check error debug log for any issues.

Network-Destroy all GameObjects, PhotonViews and their RPCs in the room. Removes anything buffered from the server. Can only be called by Master Client (for anyone).

Can only be called by Master Client (for anyone).

Unlike the Destroy methods, this will remove anything from the server's room buffer. If your game

buffers anything beyond Instantiate and RPC calls, that will be cleaned as well from server.

Destroying all includes:

- Remove anything from the server's room buffer (Instantiate, RPCs, anything buffered).

- Sending a message to other clients to destroy everything locally, too (affected by network lag).

Destroying networked objects works only if they got created with PhotonNetwork.Instantiate().

Objects loaded with a scene are ignored, no matter if they have PhotonView components.

Nothing. Check error debug log for any issues.

Remove all buffered RPCs from server that were sent by targetPlayer. Can only be called on local player (for "self") or Master Client (for anyone).

This method requires either:

- This is the targetPlayer's client.

- This client is the Master Client (can remove any PhotonPlayer's RPCs).

If the targetPlayer calls RPCs at the same time that this is called,

network lag will determine if those get buffered or cleared like the rest.

This player's buffered RPCs get removed from server buffer.

Remove all buffered RPCs from server that were sent via targetPhotonView. The Master Client and the owner of the targetPhotonView may call this.

This method requires either:

- The targetPhotonView is owned by this client (Instantiated by it).

- This client is the Master Client (can remove any PhotonView's RPCs).

RPCs buffered for this PhotonView get removed from server buffer.

Remove all buffered RPCs from server that were sent in the targetGroup, if this is the Master Client or if this controls the individual PhotonView.

This method requires either:

- This client is the Master Client (can remove any RPCs per group).

- Any other client: each PhotonView is checked if it is under this client's control. Only those RPCs are removed.

Interest group that gets all RPCs removed.

Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!

Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!

Enabledisable receiving on given group (applied to PhotonViews)

The interest group to affect.

Sets if receiving from group to enabled (or not).

Enabledisable receiving on given groups (applied to PhotonViews)

The interest groups to enable (or null).

The interest groups to disable (or null).

Enabledisable sending on given group (applied to PhotonViews)

The interest group to affect.

Sets if sending to group is enabled (or not).

Enabledisable sending on given groups (applied to PhotonViews)

The interest groups to enable sending on (or null).

The interest groups to disable sending on (or null).

Sets level prefix for PhotonViews instantiated later on. Don't set it if you need only one!

Important: If you don't use multiple level prefixes, simply don't set this value. The

default value is optimized out of the traffic.

This won't affect existing PhotonViews (they can't be changed yet for existing PhotonViews).

Messages sent with a different level prefix will be received but not executed. This affects

RPCs, Instantiates and synchronization.

Be aware that PUN never resets this value, you'll have to do so yourself.

Max value is short.MaxValue = 32767

Helper function which is called inside this class to erify if certain functions can be used (e.g. RPC when not connected)

Wraps loading a level to pause the network mesage-queue. Optionally syncs the loaded level in a room.

While loading levels, it makes sense to not dispatch messages received by other players.

This method takes care of that by setting PhotonNetwork.isMessageQueueRunning = false and enabling

the queue when the level was loaded.

To sync the loaded level in a room, set PhotonNetwork.automaticallySyncScene to true.

The Master Client of a room will then sync the loaded level with every other player in the room.

You should make sure you don't fire RPCs before you load another scene (which doesn't contain

the same GameObjects and PhotonViews). You can call this in OnJoinedRoom.

This uses Application.LoadLevel.

Number of the level to load. When using level numbers, make sure they are identical on all clients.

Wraps loading a level to pause the network mesage-queue. Optionally syncs the loaded level in a room.

While loading levels, it makes sense to not dispatch messages received by other players.

This method takes care of that by setting PhotonNetwork.isMessageQueueRunning = false and enabling

the queue when the level was loaded.

To sync the loaded level in a room, set PhotonNetwork.automaticallySyncScene to true.

The Master Client of a room will then sync the loaded level with every other player in the room.

You should make sure you don't fire RPCs before you load another scene (which doesn't contain

the same GameObjects and PhotonViews). You can call this in OnJoinedRoom.

This uses Application.LoadLevel.

Name of the level to load. Make sure it's available to all clients in the same room.

This operation makes Photon call your custom web-service by name (path) with the given parameters.

This is a server-side feature which must be setup in the Photon Cloud Dashboard prior to use.

See the Turnbased Feature Overview for a short intro.

http:doc.exitgames.comenturnbasedcurrentgetting-startedfeature-overview

The Parameters will be converted into JSon format, so make sure your parameters are compatible.

See PhotonNetworkingMessage.OnWebRpcResponse on how to get a response.

It's important to understand that the OperationResponse only tells if the WebRPC could be called.

The content of the response contains any values your web-service sent and the errorsuccess code.

In case the web-service failed in some way, an error code and a debug message are usually inside

the OperationResponse.

The class WebRpcResponse is a helper-class that extracts the most valuable content from the WebRPC

response.

Example callback implementation:

public void OnWebRpcResponse(OperationResponse response)

{

WebRpcResponse webResponse = new WebRpcResponse(operationResponse);

if (webResponse.ReturnCode != 0) { ...

}

switch (webResponse.Name) { ...

}

and so on

}




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.538 lượt xem

Gõ tìm kiếm nhanh...